1 var REST = function()
  2 {
  3 	var REST = {};
  4 	var myResult = [];
  5 	var myHasErrors = false;
  6 	logRequest();
  7 
  8 	//Field PropertyWrappers to collect the version number and the replaced date
  9 	var kReplaceDate = new Property("http://mediabeacon.com/ns/default/1.0/", "replaceDate");
 10 
 11 	/**
 12 	 * the callback for the REST call (savedSelections.js, directories.js, etc)
 13 	 * @type {null}
 14 	 */
 15 	var myCallback = null;
 16 
 17 	/**
 18 	 * All of the parameters given in the request
 19 	 * @type {{}}
 20 	 */
 21 	var myRequestParameters = getParameters();
 22 
 23 	/**
 24 	 * Enable or disable adding data like name, path, height, etc...
 25 	 * @type {boolean}
 26 	 */
 27 	var myVerbose = !!myRequestParameters.verbose ? myRequestParameters.verbose: false;
 28 
 29 	/**
 30 	 * add the mtime to the response if the mtime parameter is set to true
 31 	 * @type {boolean}
 32 	 */
 33 	var myMtime = !!myRequestParameters.mtime ? myRequestParameters.mtime: false;
 34 
 35 	/**
 36 	 * Parameter to collect the document report.
 37 	 * this is slow so we should exclude by default
 38 	 * @type {boolean}
 39 	 */
 40 	var myCollectDocumentReport = !!myRequestParameters.documentLinks ? myRequestParameters.documentLinks: false;
 41 
 42 	/**
 43 	 * Controls whether processing will stop on the first error.  (Default:  true.)
 44 	 * @type {boolean}
 45 	 */
 46 	var myStopOnFirstError = true;
 47 
 48 	/**
 49 	 * Adds an error object to the response
 50 	 *
 51 	 * @param theHttpCode
 52 	 * @param theErrorMessage
 53 	 * @param theException
 54 	 */
 55 	REST.pushError = function(theHttpCode, theErrorMessage, theException)
 56 	{
 57 		// If an error is not provided then we should just make it a 500 error.
 58 		if (!theHttpCode)
 59 		{
 60 			theHttpCode = REST.errors.e500;
 61 		}
 62 
 63 		if (!!theException)
 64 		{
 65 			logger.error(stack(theException));
 66 		}
 67 		myHasErrors = true;
 68 
 69 		// Set the code in the header.
 70 		context.setResponseHeader('status', theHttpCode.code);
 71 
 72 		REST.push(null, {
 73 			error: {
 74 				message: theErrorMessage,
 75 				http: theHttpCode,
 76 			}
 77 		});
 78 	};
 79 
 80 	/**
 81 	 * Returns true if we have encountered an error
 82 	 */
 83 	REST.hasErrors = function()
 84 	{
 85 		return myHasErrors;
 86 	};
 87 
 88 	/**
 89 	 * Push an object into the response
 90 	 */
 91 	REST.push = function(theFileOrFolder, theJSON, theDoFilter)
 92 	{
 93 		if (!!theFileOrFolder)
 94 		{
 95 			theJSON = REST.getInfo(theFileOrFolder, theJSON);
 96 		}
 97 		if (theDoFilter && !!theJSON && !REST.filterMatch(theJSON))
 98 		{
 99 			return;
100 		}
101 		myResult[myResult.length] = theJSON;
102 	};
103 
104 	/**
105 	 * Remove the last added object to myResult.
106 	 * Not commonly used.
107 	 *
108 	 * Helpful for delete because we can add the file/folder to myResult with all of its asset info, then delete it.
109 	 * if we fail to delete the item, we still need to manually pop the object from myResult.
110 	 */
111 	REST.pop = function()
112 	{
113 		myResult.length --;
114 	};
115 
116 	/**
117 	 * Set the callback
118 	 * @param theCallback a function that takes in a managed file and pushes objects to the response object
119 	 */
120 	REST.setCallback = function(theCallback)
121 	{
122 		myCallback = theCallback;
123 	};
124 
125 	/**
126 	 * Sets whether to stop processing the REST call on the first error.  (Default is true.)
127 	 * @param theStop true if so, false if no.
128 	 */
129 	REST.setStopOnFirstError = function (theStop)
130 	{
131 		myStopOnFirstError = theStop;
132 	};
133 
134 	/**
135 	 * Checks whether to stop processing the REST call on the first error.
136 	 * @return theStop true if so, false if no.
137 	 */
138 	REST.getStopOnFirstError = function ()
139 	{
140 		return myStopOnFirstError;
141 	};
142 
143 	/**
144 	 * Executes the callback with the array of asset id's or the resolver url
145 	 */
146 	REST.execute = function(theExecuteOverParameter)
147 	{
148 		try
149 		{
150 			var aResolver = null;
151 
152 			if (!!myRequestParameters.resolver)
153 			{
154 				//Iterate over Resolver
155 				aResolver = myRequestParameters.resolver;
156 				searchManager.searchByResolverUrl(aResolver, context.getUser().userId, errorCheckingCallback);
157 			} else if (!!theExecuteOverParameter)
158 			{
159 				//Iterate over the passed in parameter name
160 				var aValues = myRequestParameters[theExecuteOverParameter];
161 				if (!!aValues)
162 				{
163 					if (!Array.isArray(aValues))
164 					{
165 						aValues = [aValues];
166 					}
167 					for (var i in aValues)
168 					{
169 						errorCheckingCallback(aValues[i]);
170 					}
171 				}
172 			} else if (!!myRequestParameters.ids)
173 			{
174 				//Iterate over asset ids
175 				if (!Array.isArray(myRequestParameters.ids))
176 				{
177 					myRequestParameters.ids = [myRequestParameters.ids];
178 				}
179 				myRequestParameters.ids = searchManager.filterByACL(myRequestParameters.ids);
180 				for (var i in myRequestParameters.ids)
181 				{
182 					errorCheckingCallback(fileManager.getFileObjectById(myRequestParameters.ids[i]));
183 				}
184 			} else
185 			{
186 				//just execute the callback
187 				errorCheckingCallback();
188 			}
189 		} catch (anE)
190 		{
191 			REST.pushError(REST.errors.e500, "Failed to execute.  Check the workflow logs for more information", anE);
192 		} finally {
193 			REST.setStopOnFirstError(true);
194 		}
195 		return REST.formatResponse(myResult);
196 	};
197 
198 	/**
199 	 * Returns a string to be returned from the workflow.
200 	 * Uses JSONP if the "callback" parameter is defined.
201 	 * if the "pretty" parameter is set to true we will format the response with newlines in the JSON
202 	 */
203 	REST.formatResponse = function(theResponseObject)
204 	{
205 		var aResponseString = "";
206 		if (!!myRequestParameters.pretty)
207 		{
208 			aResponseString = JSON.stringify(theResponseObject, null, 2);
209 		} else
210 		{
211 			aResponseString = JSON.stringify(theResponseObject);
212 		}
213 		var aCallback = context.getParameter("callback");
214 		return !!aCallback ? aCallback + "(" + aResponseString + ");" : aResponseString;
215 	};
216 
217 	REST.filterMatch = function(theObject)
218 	{
219 		var anAllowForFilter = ["id", "name", "path", "height", "width", "bytes", "lastModified", "mimeType", "description", "type", "shared", "public", "count"];
220 		for (var aParameter in myRequestParameters)
221 		{
222 			if (anAllowForFilter.indexOf(aParameter) < 0)
223 			{
224 				continue;
225 			}
226 			var aFilterValue = myRequestParameters[aParameter];
227 			var anAssetValue = theObject[aParameter];
228 			if (anAssetValue === undefined)
229 			{
230 				//don't filter on undefined attributes
231 				return false;
232 			}
233 			if (!isNaN(anAssetValue))
234 			{
235 				//number values
236 				if (isNaN(aFilterValue) && (aFilterValue.indexOf(">") == 0 || aFilterValue.indexOf("<") == 0))
237 				{
238 					//Range filter
239 					var aGtLt = aFilterValue.substring(0, 1);
240 					var aNum = parseInt(aFilterValue.substring(1));
241 					if ((aGtLt == ">" && anAssetValue < aNum) || (aGtLt == "<" && anAssetValue > aNum))
242 					{
243 						return false;
244 					}
245 				} else if (anAssetValue != aFilterValue)
246 				{
247 					return false;
248 				}
249 			} else
250 			{
251 				if (!!aFilterValue && !!anAssetValue)
252 				{
253 					if (aFilterValue.toString().indexOf("*") >= 0)
254 					{
255 						var aRegEx = new RegExp("^" + aFilterValue.split("*").join(".*")+ "$");
256 						if (!aRegEx.test(anAssetValue))
257 						{
258 							return false;
259 						}
260 					} else if (anAssetValue != aFilterValue)
261 					{
262 						return false;
263 					}
264 				}
265 			}
266 
267 		}
268 		return true;
269 	};
270 
271 	/**
272 	 * Gets the standard asset info given an array of asset ids
273 	 * @param theAssetIds
274 	 */
275 	REST.getAssetInfo = function(theAssetIds)
276 	{
277 		var anAssetInfo = [];
278 		for (var i in theAssetIds)
279 		{
280 			var anAsset = fileManager.getFileObjectById(theAssetIds[i]);
281 			if (!!anAsset)
282 			{
283 				anAssetInfo.push(REST.getInfo(anAsset, {}));
284 			} else {
285 				logger.config("REST.getAssetInfo() asset doesn't exist by id: " + theAssetIds[i]);
286 			}
287 		}
288 		return anAssetInfo;
289 	};
290 
291 	/**
292 	 * returns the acl relative path given the MB relative path
293 	 * @param theFullPath
294 	 * @returns {string|void|*|XML}
295 	 */
296 	REST.getACLRelativePath = function(theFullPath)
297 	{
298 		var aUsersRootPath  = context.getACL().getRootPath();
299 		if (aUsersRootPath == null && aUsersRootPath == "")
300 		{
301 			var aUsersAcls = context.getUser().getPrimaryGroup().getACLs();
302 			if (aUsersAcls.length <= 0)
303 			{
304 				aUsersRootPath = null;
305 			} else
306 			{
307 				aUsersRootPath = aUsersAcls[0].getRootPath();
308 			}
309 		}
310 		if (aUsersRootPath == null)
311 		{
312 			throw "Couldn't find ACL for current user";
313 		}
314 		var aPath = theFullPath.replace(aUsersRootPath, "");
315 		return aPath == "" ? "/" : aPath;
316 	};
317 
318 	/**
319 	 * Adds the acl root path to thePath if the user is in a subroot acl
320 	 * @param thePath
321 	 * @returns {*}
322 	 */
323 	REST.getFullPath = function(thePath)
324 	{
325 		thePath = !thePath ? "" : thePath;
326 		var aPath = context.getACL().getRootPath() + thePath;
327 		//normalize any paths like Assets//test/ to Assets/test/
328 		aPath = aPath.split("//").join("/");
329 		return aPath;
330 	};
331 
332 	/**
333 	 * Is file?
334 	 *
335 	 * @param theFile the file to check
336 	 */
337 	REST.isFile = function (theFile)
338 	{
339 		return fileManager.isFile(theFile.path) || theFile instanceof UnmanagedFile;
340 	};
341 
342 	/**
343 	 * Returns the apikey request parameter and value in string form
344 	 * @returns {string}
345 	 */
346 	REST.getAuthParam = function()
347 	{
348 		return "apikey=" + apiKeyManager.getOrCreateApiKey("", context.getUser().username) + "&acl_id=" + context.getACL().id;
349 	};
350 
351 	/**
352 	 * Given a field id like "http://purl.org/dc/elements/1.1/ subject" or "database record_id" or "record_id"
353 	 * @param theFieldId
354 	 * @returns {Property}
355 	 */
356 	REST.getProperty = function(theFieldId)
357 	{
358 		try
359 		{
360 			if (theFieldId.indexOf(" ") < 0)
361 			{
362 				//assume its a DB field
363 				return new Property("database", theFieldId);
364 			} else
365 			{
366 				var aFieldSet = theFieldId.split(' ');
367 				return new Property(aFieldSet[0], aFieldSet[1]);
368 			}
369 		} catch (anE)
370 		{
371 			REST.pushError(REST.errors.e404, "Failed to find the field for the field ID: " + theFieldId, anE);
372 			return null;
373 		}
374 	};
375 
376 	/**
377 	 * Call another REST workflow with the parameters
378 	 * @param theWorkflowName
379 	 * @param theParameters
380 	 */
381 	REST.callRESTWorkflow = function(theWorkflowName, theParameters)
382 	{
383 		var aParameters = new Parameters();
384 		if (!!myRequestParameters["verbose"])
385 		{
386 			aParameters.put("verbose", myRequestParameters["verbose"]);
387 		}
388 		if (!!myRequestParameters["fields"])
389 		{
390 			aParameters.put("fields", myRequestParameters["fields"]);
391 		}
392 		for (var aParam in theParameters)
393 		{
394 			aParameters.put(aParam, JSON.stringify(theParameters[aParam]));
395 		}
396 		var aWorkflow = new Workflow("Renditions/Workflows/_internal/restapi/v2/" + theWorkflowName + ".xmpwf");
397 		var aResponse = aWorkflow.trigger(aParameters);
398 		try
399 		{
400 			return JSON.parse(aResponse);
401 		} catch(anE)
402 		{
403 			return aResponse;
404 		}
405 	};
406 
407 	REST.AssetTriggers = Object.freeze({
408 		Modified: "asset modified",
409 		Added: "asset added",
410 		Removed: "asset removed",
411 		Downloaded: "asset downloaded"
412 	});
413 
414 	REST.triggerAssetBasedWorkflows = function(theType, theFile, theModificationsIfAny)
415 	{
416 		var aStub = {};
417 		if (!context.getParameter("triggerAssetBasedWorkflow", true))
418 		{
419 			return false;
420 		}
421 
422 		aStub.ok = false;
423 		aStub.type = theType;
424 
425 		switch (theType)
426 		{
427 			case REST.AssetTriggers.Modified:
428 				workflowManager.triggerAssetModified(theFile, theModificationsIfAny);
429 				aStub.ok = true;
430 				aStub.changes = theModificationsIfAny;
431 				break;
432 			case REST.AssetTriggers.Added:
433 				workflowManager.triggerAssetAdded(theFile);
434 				aStub.ok = true;
435 				break;
436 			case REST.AssetTriggers.Removed:
437 				workflowManager.triggerAssetRemoved(theFile);
438 				aStub.ok = true;
439 				break;
440 			case REST.AssetTriggers.Downloaded:
441 				workflowManager.triggerAssetDownloaded(theFile);
442 				aStub.ok = true;
443 				break;
444 		}
445 
446 		return aStub;
447 	};
448 
449 	REST.addToChangeList = function(theChangeList, theProperty, theOld, theNew)
450 	{
451 		theChangeList[theProperty.fieldId] = {
452 			"old": typeof(theOld) === "object" ? theOld : theOld.toString(),
453 			"new": typeof(theNew) === "object" ? theNew : theNew.toString(),
454 			"type": theProperty.getFieldType()
455 		};
456 
457 		return theChangeList;
458 	};
459 
460 	REST.formatDiscussionList = function(theDiscussionSet, theLimit, theOrder)
461 	{
462 		var aFormattedList = [];
463 
464 		if (theDiscussionSet != null)
465 		{
466 			// Set the limit if it's too large.
467 			if (theLimit && theLimit > theDiscussionSet.length)
468 			{
469 				theLimit = theDiscussionSet.length;
470 			}
471 
472 			// Set the start: either 0 or the end of the array.
473 			var aStartIndex = theOrder === 'desc' ? theDiscussionSet.length - 1 : 0;
474 
475 			// Pick where to stop: either the limit requested or the discussion set length or 0, depending on the order.
476 			var aLimit = !isNaN(theLimit) ? theLimit : theDiscussionSet.length;
477 
478 			// Set the actual array index.
479 			var aPlacementIndex = 0;
480 
481 			// Loop through them and add a useful item to the array.
482 			while (true)
483 			{
484 				aFormattedList[aPlacementIndex] = {};
485 
486 				// Get the sub entries in the discussion.
487 				var aSubFields = theDiscussionSet.getItemAt(aStartIndex).getFields();
488 
489 				// Loop through all the sub entry's fields and place them in the appropriate array.
490 				for (var j = 0; j < aSubFields.length; j++)
491 				{
492 					aFormattedList[aPlacementIndex][aSubFields[j].name] = theDiscussionSet.getItemAt(aStartIndex).getField(aSubFields[j]).toString()
493 				}
494 
495 				aPlacementIndex++;
496 
497 				// Descending order.
498 				aLimit--;
499 				if (aLimit <= 0)
500 				{
501 					break;
502 				}
503 				if (theOrder === 'desc')
504 				{
505 					aStartIndex--;
506 					if (aStartIndex < 0)
507 					{
508 						break;
509 					}
510 				} else
511 				{
512 					aStartIndex++;
513 					if (aStartIndex > theDiscussionSet.length - 1)
514 					{
515 						break;
516 					}
517 				}
518 			}
519 		}
520 
521 		return aFormattedList;
522 	};
523 
524 	/**
525 	 * Adds the standard response data requested by the user
526 	 * @param theFileOrFolder
527 	 * @param theJSON
528 	 */
529 	REST.getInfo = function(theFileOrFolder, theJSON)
530 	{
531 		logger.fine("file or folder: " + theFileOrFolder + " " + theJSON);
532 		theJSON = !theJSON ? {} : theJSON;
533 		if (fileManager.isFile(theFileOrFolder.path))
534 		{
535 			theJSON.id = theFileOrFolder.assetId;
536 			if (myVerbose)
537 			{
538 				theJSON.name = theFileOrFolder.name;
539 				theJSON.path = REST.getACLRelativePath(theFileOrFolder.path);
540 				theJSON.directoryId = theFileOrFolder.parent.directoryId;
541 				theJSON.height = theFileOrFolder.height;
542 				theJSON.width = theFileOrFolder.width;
543 				theJSON.bytes = theFileOrFolder.fileSizeIncludingMetadata;
544 				theJSON.lastModified = theFileOrFolder.lastModified;
545 				if (!!theFileOrFolder.fileNameExtension || !!kMimeMap[theFileOrFolder.fileNameExtension.toLowerCase()])
546 				{
547 					theJSON.mimeType = kMimeMap[theFileOrFolder.fileNameExtension.toLowerCase()];
548 				} else
549 				{
550 					logger.error("Failed to find a mimeType for the file extension: " + theFileOrFolder.fileNameExtension);
551 				}
552 				theJSON.previews = {};
553 				theJSON.previews.thumbnail = theFileOrFolder.getImageURL("thumbnails").replace("..", context.getServerURL());
554 				theJSON.previews.viewex = theFileOrFolder.getImageURL("viewex").replace("..", context.getServerURL());
555 				theJSON.previews.high = theFileOrFolder.getImageURL("high").replace("..", context.getServerURL());
556 				theJSON.previews.downloadUrl = context.getServerURL() + "/servlet/dload/" + theFileOrFolder.name + "?id=" + theFileOrFolder.encodedAssetId;
557 				theJSON.replaceDate = theFileOrFolder.xmp.meta.getField(kReplaceDate);
558 				theJSON.replaceDate = !!theJSON.replaceDate ? parseInt(theJSON.replaceDate) : 0;
559 				var aVersionNumber = versionManager.getVersionCount(
560 					theFileOrFolder.assetId,
561 					"",
562 					["Named"]
563 				);
564 				theJSON.versionNumber = !aVersionNumber || isNaN(aVersionNumber) ? 0 : parseInt(aVersionNumber);
565 				var aVersionAssets = versionManager.getVersions(
566 					theFileOrFolder.assetId,
567 					["Named"],
568 					aVersionNumber
569 				);
570 				if (!!aVersionAssets && aVersionAssets.length > 0)
571 				{
572 					var aVersionIds = [];
573 					for (var i = 0; i < aVersionAssets.length; i++)
574 					{
575 						var aVersionAsset = aVersionAssets[i];
576 						aVersionIds.push(aVersionAsset.assetId);
577 					}
578 					theJSON.versionIds = aVersionIds;
579 				}
580 			}
581 
582 			if (myCollectDocumentReport)
583 			{
584 				var anExt = theFileOrFolder.fileNameExtension;
585 				if (anExt == "indd" || anExt == "qxd" || anExt == "ai")
586 				{
587 					//check for linked assets
588 					theJSON.documentLinks = [];
589 					var aLinks = linkManager.getEmbeddedFiles(theFileOrFolder);
590 					for (var i in aLinks)
591 					{
592 						var aLink = aLinks[i];
593 						theJSON.documentLinks[theJSON.documentLinks.length] = REST.getInfo(aLink.getManagedFile(), {
594 							linkPath: aLink.filePath,
595 						});
596 					}
597 				}
598 			}
599 
600 			if (myMtime)
601 			{
602 				//mtime from the db. More specific than lastModified.
603 				theJSON.mtime = new SQL().queryForString("SELECT xmp_modification_db FROM editorial WHERE record_id = " + theJSON.id);
604 			}
605 
606 			//Get fields if they were provided
607 			if (!!myRequestParameters.fields && myRequestParameters.fields.length > 0)
608 			{
609 				theJSON.fields = {};
610 				var aFields = !Array.isArray(myRequestParameters.fields) ? [myRequestParameters.fields] : myRequestParameters.fields;
611 				for (var i = 0; i < aFields.length; i++)
612 				{
613 					var aFieldId = aFields[i];
614 					if (!fieldManager.canView(aFieldId, context.getUser().getViewLevel()))
615 					{
616 						logger.warning("Cannot view: " + aFieldId);
617 						continue;
618 					}
619 					var aProp = REST.getProperty(aFieldId);
620 					var aVal;
621 					if (aProp.namespace === 'database')
622 					{
623 						aVal = theFileOrFolder[aProp.name];
624 						if (aVal == null)
625 						{
626 							aVal = theFileOrFolder.getDatabaseField(aProp.name);
627 						}
628 					} else
629 					{
630 						aVal = theFileOrFolder.xmp.meta.getField(aProp);
631 						if (aVal instanceof Collection)
632 						{
633 							var aJSONVal = [];
634 							var anIterator = aVal.iterator;
635 							while (anIterator.hasMore)
636 							{
637 								var aBlock = anIterator.next;
638 								if (aBlock instanceof Resource)
639 								{
640 									//Build data block as a JSON object.
641 									var aJSONBlock = {};
642 									var aProperties = aBlock.getFields();
643 									for (var k in aProperties)
644 									{
645 										var aProperty = aProperties[k];
646 										var aBlockVal = aBlock.getField(aProperty);
647 										if (aBlockVal instanceof Collection)
648 										{
649 											aBlockVal = JSON.parse(aBlockVal);
650 										}
651 										aJSONBlock[aProperty.fieldId] = aBlockVal;
652 									}
653 									aJSONVal[aJSONVal.length] = aJSONBlock;
654 								} else
655 								{
656 									aJSONVal[aJSONVal.length] = aBlock;
657 								}
658 							}
659 							aVal = aJSONVal;
660 						}
661 					}
662 					theJSON.fields[aFieldId] = aVal;
663 				}
664 			}
665 		} else if (fileManager.isFolder(theFileOrFolder.path))
666 		{
667 			theJSON = REST.buildFolderObject(theFileOrFolder, REST.getACLRelativePath(theFileOrFolder.path), false);
668 		}
669 
670 		return theJSON;
671 	};
672 
673 	/**
674 	 * Gets all of the Parameters from the request and their values
675 	 * @returns {{}}
676 	 */
677 	function getParameters()
678 	{
679 		var aToIgnore = ["request.headers", "workflow.url.path"];
680 		var aRequestParameters = {};
681 		var aParameters = context.getParameterNames();
682 		for (var i in aParameters)
683 		{
684 			var aParamName = aParameters[i];
685 			var aParamVal = context.getParameter(aParamName);
686 			if (aToIgnore.indexOf(aParameters[i]) >= 0)
687 			{
688 				continue;
689 			}
690 			if (aParamName.indexOf("MBUploadedFile") >= 0)
691 			{
692 				//looks like we found our selves an uploaded file
693 				//add it back as its original name
694 				var anOriginal = aParamName.split("MBUploadedFile").join("");
695 				var aFileObject = context.getParameter(anOriginal);
696 				aRequestParameters[anOriginal] = {
697 					"isFile" : true,
698 					"name" : aFileObject.name,
699 					"length" : aFileObject.length
700 				}
701 			} else
702 			{
703 				aRequestParameters[aParamName] = aParamVal;
704 			}
705 		}
706 		return aRequestParameters;
707 	}
708 
709 	/**
710 	 * Formats the exception
711 	 * @param theE
712 	 * @returns {string}
713 	 */
714 	function stack(theE)
715 	{
716 		return theE + (!!theE.stack ? "\n" + theE.stack : "");
717 	}
718 
719 	/**
720 	 * executes myCallback if we haven't encountered an error already.
721 	 * @param theCallbackParameter
722 	 */
723 	function errorCheckingCallback(theCallbackParameter)
724 	{
725 		if (REST.getStopOnFirstError() && REST.hasErrors())
726 		{
727 			return;
728 		} else
729 		{
730 			try
731 			{
732 				if (!!myCallback)
733 				{
734 					myCallback(theCallbackParameter);
735 				}
736 			} catch (anE)
737 			{
738 				var aParam = !!theCallbackParameter ? theCallbackParameter : "";
739 				aParam = !!aParam.name ? aParam.name : (typeof aParam === 'object' ? JSON.stringify(aParam) : aParam.toString());
740 				REST.pushError(REST.errors.e500, "Failed to execute " + myCallback.name + "(" + (!aParam ? "" : "'" + aParam + "'") + ");", anE);
741 			}
742 		}
743 	}
744 
745 	/**
746 	 * Logs the request made to the REST workflow
747 	 */
748 	function logRequest()
749 	{
750 		var aToIgnore = ["request.headers"];
751 		var aToLog = {};
752 		var aParameters = context.getParameterNames();
753 		for (var i in aParameters)
754 		{
755 			var aParamName = aParameters[i];
756 			var aParamVal = context.getParameter(aParamName);
757 			if (aToIgnore.indexOf(aParameters[i]) >= 0)
758 			{
759 				continue;
760 			}
761 			if (aParamName.indexOf("MBUploadedFile") >= 0)
762 			{
763 				//looks like we found our selves an uploaded file
764 				//add it back as its original name
765 				var anOriginal = aParamName.split("MBUploadedFile").join("");
766 				var aFileObject = context.getParameter(anOriginal);
767 				aToLog[anOriginal] = {
768 					"isFile" : true,
769 					"name" : aFileObject.name,
770 					"length" : aFileObject.length
771 				}
772 			} else
773 			{
774 				aToLog[aParamName] = aParamVal;
775 			}
776 		}
777 		logger.config("REST API request parameters:\n " + JSON.stringify(aToLog, null, 2));
778 	}
779 
780 	/**
781 	 * Executes a search with the parameters the pageSize, pageNumber, sortDirection, and sortField
782 	 * @param theSearch
783 	 * @param theCallback the search callback
784 	 */
785 	REST.executeSearchWithPaging = function(theSearch)
786 	{
787 		var aPageSize = myRequestParameters["pageSize"];
788 		var aPageNumber = myRequestParameters["pageIndex"];
789 		var aSortDirection = myRequestParameters["sortDirection"];
790 		var aSortField = myRequestParameters["sortField"];
791 		if (!!aSortDirection && !!aSortField)
792 		{
793 			theSearch.setSortDirection(aSortDirection);
794 			theSearch.setSortField(aSortField);
795 		}
796 		aPageSize = !aPageSize ? 100 : aPageSize;
797 		aPageNumber = !aPageNumber ? 0 : aPageNumber;
798 		return theSearch.executeForArray(aPageNumber, aPageSize)
799 	};
800 
801 	REST.isVerbose = function()
802 	{
803 		return myVerbose;
804 	};
805 
806 	/**
807 	 * Initializes the JSON object for the response
808 	 * @param theFolder
809 	 * @returns {{name: *, path: (string|void|*|XML), id: *, parentId: *, resolver: string, assets: *}}
810 	 */
811 	REST.buildFolderObject = function(theFolder)
812 	{
813 		var anAclPath = REST.getACLRelativePath(theFolder.path);
814 		var aIsRoot = "/" === anAclPath;
815 		var aFolder = {
816 			"path": anAclPath,
817 			"id": theFolder.directoryId,
818 			"parentId": aIsRoot ? undefined : theFolder.parent.directoryId,
819 		};
820 		if (REST.isVerbose())
821 		{
822 			Object.assign(aFolder, {
823 				"name" : aIsRoot ? "Index": theFolder.name,
824 				"resolver" : "directory://" + theFolder.directoryId,
825 			});
826 		}
827 		return aFolder;
828 	};
829 
830 	/**
831 	 * Gets an array of paths of all of the directories in this acl
832 	 * @param theFolder
833 	 * @param theDepth
834 	 * @param theParentJSON
835 	 * @param theIsHierarchy return a JSON data structure with children folders nested in other folders
836 	 * @returns {Array} flat list of all found directories.
837 	 */
838 	REST.getChildDirectories = function(theFolder, theDepth, theIsHierarchy, theParentJSON)
839 	{
840 		theParentJSON = !!theParentJSON ? theParentJSON : REST.buildFolderObject(theFolder);
841 		var aAllChildren = [];
842 		if (theDepth != 0) //-1 should find all children directories
843 		{
844 			var aChildren = theFolder.children;
845 			if (theIsHierarchy)
846 			{
847 				theParentJSON.children = [];
848 			}
849 			for (var i in aChildren)
850 			{
851 				var aChild = aChildren[i];
852 				if (aChild.path === "Renditions/")
853 				{
854 					continue;
855 				}
856 				var aChildJSON = REST.buildFolderObject(aChild);
857 				if (theIsHierarchy)
858 				{
859 					theParentJSON.children.push(aChildJSON);
860 				}
861 				aAllChildren.push(aChildJSON);
862 				var aGrandChildren = REST.getChildDirectories(aChild, theDepth - 1, theIsHierarchy, aChildJSON);
863 				aAllChildren.push.apply(aAllChildren, aGrandChildren);
864 			}
865 		} else if (theFolder.children.length > 0)
866 		{
867 			theParentJSON.hasChildren = true;
868 		}
869 		return aAllChildren;
870 	};
871 
872 	/**
873 	 * Get facets as a JSON array from solr.
874 	 *
875 	 * @param theFieldId the field id
876 	 * @param thePageSize the page size
877 	 * @param theIncludedSearch the included search
878 	 * @param theHierarchyLevel the hierarchy level
879 	 * @param thePageNumber the page number
880 	 * @returns {Array}
881 	 */
882 	REST.getFacets = function(theFieldId, thePageSize, theIncludedSearch, theHierarchyLevel, thePageNumber)
883 	{
884 		theFieldId = theFieldId.replace("database ", "");
885 		var aSearch = !!theIncludedSearch ? theIncludedSearch : new Search();
886 		var aSolrConfig = new SolrConfig();
887 
888 		aSolrConfig.addFacetField(theFieldId);
889 		aSolrConfig.setNumberResults(theFieldId, thePageSize);
890 		aSolrConfig.setHierarchyLevel(theFieldId, !!theHierarchyLevel ? theHierarchyLevel : 0);
891 
892 		//Return a facet map from the search
893 		var aResults = [];
894 		var aFacet = aSearch.getTermsWithLimit(
895 			aSolrConfig,
896 			!!thePageNumber ? thePageNumber : 0,
897 			!!thePageSize ? thePageSize : 1000
898 		);
899 		if (!!aFacet)
900 		{
901 			var aFacetFieldId = aFacet.getFieldId();
902 			if (aFacetFieldId == theFieldId)
903 			{
904 				for (var i = 0; i < aFacet.size(); i++)
905 				{
906 					var aFacetLabel = aFacet.getValue(i).getLabel();
907 					if (aFacetLabel != "MBFacetMissing")
908 					{
909 						aResults[aResults.length] = {
910 							value: aFacetLabel,
911 							count: aFacet.getValue(i).getCount(),
912 							raw: aFacet.getValue(i).getRawLabel()
913 						};
914 					}
915 				}
916 			}
917 		}
918 		return aResults;
919 	};
920 
921 	REST.errors = {
922 		// 400
923 		e400: {name: "Bad Request", code: 400},
924 		e401: {name: "Unauthorized", code: 401},
925 		e403: {name: "Forbidden", code: 403},
926 		e404: {name: "Not Found", code: 404},
927 		e405: {name: "Method Not Allowed", code: 405},
928 		e406: {name: "Not Acceptable", code: 406},
929 		e409: {name: "Conflict", code: 409},
930 
931 		// 500
932 		e500: {name: "Internal Server Error", code: 500},
933 	};
934 
935 	return REST;
936 };
937 
938 
939 /**
940  * ext to mime type mapping
941  */
942 var kMimeMap = {
943 	"x3d":"application/vnd.hzn-3d-crossword",
944 	"3gp":"video/3gpp",
945 	"3g2":"video/3gpp2",
946 	"mseq":"application/vnd.mseq",
947 	"pwn":"application/vnd.3m.post-it-notes",
948 	"plb":"application/vnd.3gpp.pic-bw-large",
949 	"psb":"application/vnd.3gpp.pic-bw-small",
950 	"pvb":"application/vnd.3gpp.pic-bw-var",
951 	"tcap":"application/vnd.3gpp2.tcap",
952 	"7z":"application/x-7z-compressed",
953 	"abw":"application/x-abiword",
954 	"ace":"application/x-ace-compressed",
955 	"acc":"application/vnd.americandynamics.acc",
956 	"acu":"application/vnd.acucobol",
957 	"atc":"application/vnd.acucorp",
958 	"adp":"audio/adpcm",
959 	"aab":"application/x-authorware-bin",
960 	"aam":"application/x-authorware-map",
961 	"aas":"application/x-authorware-seg",
962 	"air":"application/vnd.adobe.air-application-installer-package+zip",
963 	"swf":"application/x-shockwave-flash",
964 	"fxp":"application/vnd.adobe.fxp",
965 	"pdf":"application/pdf",
966 	"ppd":"application/vnd.cups-ppd",
967 	"dir":"application/x-director",
968 	"xdp":"application/vnd.adobe.xdp+xml",
969 	"xfdf":"application/vnd.adobe.xfdf",
970 	"aac":"audio/x-aac",
971 	"ahead":"application/vnd.ahead.space",
972 	"azf":"application/vnd.airzip.filesecure.azf",
973 	"azs":"application/vnd.airzip.filesecure.azs",
974 	"azw":"application/vnd.amazon.ebook",
975 	"ami":"application/vnd.amiga.ami",
976 	"apk":"application/vnd.android.package-archive",
977 	"cii":"application/vnd.anser-web-certificate-issue-initiation",
978 	"fti":"application/vnd.anser-web-funds-transfer-initiation",
979 	"atx":"application/vnd.antix.game-component",
980 	"dmg":"application/x-apple-diskimage",
981 	"mpkg":"application/vnd.apple.installer+xml",
982 	"aw":"application/applixware",
983 	"les":"application/vnd.hhe.lesson-player",
984 	"swi":"application/vnd.aristanetworks.swi",
985 	"s":"text/x-asm",
986 	"atomcat":"application/atomcat+xml",
987 	"atomsvc":"application/atomsvc+xml",
988 	"atom":"application/atom+xml",
989 	"xml":"application/atom+xml",
990 	"ac":"application/pkix-attr-cert",
991 	"aif":"audio/x-aiff",
992 	"avi":"video/x-msvideo",
993 	"aep":"application/vnd.audiograph",
994 	"dxf":"image/vnd.dxf",
995 	"dwf":"model/vnd.dwf",
996 	"par":"text/plain-bas",
997 	"bcpio":"application/x-bcpio",
998 	"bin":"application/octet-stream",
999 	"bmp":"image/bmp",
1000 	"torrent":"application/x-bittorrent",
1001 	"cod":"application/vnd.rim.cod",
1002 	"mpm":"application/vnd.blueice.multipass",
1003 	"bmi":"application/vnd.bmi",
1004 	"sh":"application/x-sh",
1005 	"btif":"image/prs.btif",
1006 	"rep":"application/vnd.businessobjects",
1007 	"bz":"application/x-bzip",
1008 	"bz2":"application/x-bzip2",
1009 	"csh":"application/x-csh",
1010 	"c":"text/x-c",
1011 	"cdxml":"application/vnd.chemdraw+xml",
1012 	"css":"text/css",
1013 	"cdx":"chemical/x-cdx",
1014 	"cml":"chemical/x-cml",
1015 	"csml":"chemical/x-csml",
1016 	"cdbcmsg":"application/vnd.contact.cmsg",
1017 	"cla":"application/vnd.claymore",
1018 	"c4g":"application/vnd.clonk.c4group",
1019 	"sub":"image/vnd.dvb.subtitle",
1020 	"cdmia":"application/cdmi-capability",
1021 	"cdmic":"application/cdmi-container",
1022 	"cdmid":"application/cdmi-domain",
1023 	"cdmio":"application/cdmi-object",
1024 	"cdmiq":"application/cdmi-queue",
1025 	"c11amc":"application/vnd.cluetrust.cartomobile-config",
1026 	"c11amz":"application/vnd.cluetrust.cartomobile-config-pkg",
1027 	"ras":"image/x-cmu-raster",
1028 	"dae":"model/vnd.collada+xml",
1029 	"csv":"text/csv",
1030 	"cpt":"application/mac-compactpro",
1031 	"wmlc":"application/vnd.wap.wmlc",
1032 	"cgm":"image/cgm",
1033 	"ice":"x-conference/x-cooltalk",
1034 	"cmx":"image/x-cmx",
1035 	"xar":"application/vnd.xara",
1036 	"cmc":"application/vnd.cosmocaller",
1037 	"cpio":"application/x-cpio",
1038 	"clkx":"application/vnd.crick.clicker",
1039 	"clkk":"application/vnd.crick.clicker.keyboard",
1040 	"clkp":"application/vnd.crick.clicker.palette",
1041 	"clkt":"application/vnd.crick.clicker.template",
1042 	"clkw":"application/vnd.crick.clicker.wordbank",
1043 	"wbs":"application/vnd.criticaltools.wbs+xml",
1044 	"cryptonote":"application/vnd.rig.cryptonote",
1045 	"cif":"chemical/x-cif",
1046 	"cmdf":"chemical/x-cmdf",
1047 	"cu":"application/cu-seeme",
1048 	"cww":"application/prs.cww",
1049 	"curl":"text/vnd.curl",
1050 	"dcurl":"text/vnd.curl.dcurl",
1051 	"mcurl":"text/vnd.curl.mcurl",
1052 	"scurl":"text/vnd.curl.scurl",
1053 	"car":"application/vnd.curl.car",
1054 	"pcurl":"application/vnd.curl.pcurl",
1055 	"cmp":"application/vnd.yellowriver-custom-menu",
1056 	"dssc":"application/dssc+der",
1057 	"xdssc":"application/dssc+xml",
1058 	"deb":"application/x-debian-package",
1059 	"uva":"audio/vnd.dece.audio",
1060 	"uvi":"image/vnd.dece.graphic",
1061 	"uvh":"video/vnd.dece.hd",
1062 	"uvm":"video/vnd.dece.mobile",
1063 	"uvu":"video/vnd.uvvu.mp4",
1064 	"uvp":"video/vnd.dece.pd",
1065 	"uvs":"video/vnd.dece.sd",
1066 	"uvv":"video/vnd.dece.video",
1067 	"dvi":"application/x-dvi",
1068 	"seed":"application/vnd.fdsn.seed",
1069 	"dtb":"application/x-dtbook+xml",
1070 	"res":"application/x-dtbresource+xml",
1071 	"ait":"application/vnd.dvb.ait",
1072 	"svc":"application/vnd.dvb.service",
1073 	"eol":"audio/vnd.digital-winds",
1074 	"djvu":"image/vnd.djvu",
1075 	"dtd":"application/xml-dtd",
1076 	"mlp":"application/vnd.dolby.mlp",
1077 	"wad":"application/x-doom",
1078 	"dpg":"application/vnd.dpgraph",
1079 	"dra":"audio/vnd.dra",
1080 	"dfac":"application/vnd.dreamfactory",
1081 	"dts":"audio/vnd.dts",
1082 	"dtshd":"audio/vnd.dts.hd",
1083 	"dwg":"image/vnd.dwg",
1084 	"geo":"application/vnd.dynageo",
1085 	"es":"application/ecmascript",
1086 	"mag":"application/vnd.ecowin.chart",
1087 	"mmr":"image/vnd.fujixerox.edmics-mmr",
1088 	"rlc":"image/vnd.fujixerox.edmics-rlc",
1089 	"exi":"application/exi",
1090 	"mgz":"application/vnd.proteus.magazine",
1091 	"epub":"application/epub+zip",
1092 	"eml":"message/rfc822",
1093 	"nml":"application/vnd.enliven",
1094 	"xpr":"application/vnd.is-xpr",
1095 	"xif":"image/vnd.xiff",
1096 	"xfdl":"application/vnd.xfdl",
1097 	"emma":"application/emma+xml",
1098 	"ez2":"application/vnd.ezpix-album",
1099 	"ez3":"application/vnd.ezpix-package",
1100 	"fst":"image/vnd.fst",
1101 	"fvt":"video/vnd.fvt",
1102 	"fbs":"image/vnd.fastbidsheet",
1103 	"fe_launch":"application/vnd.denovo.fcselayout-link",
1104 	"f4v":"video/x-f4v",
1105 	"flv":"video/x-flv",
1106 	"fpx":"image/vnd.fpx",
1107 	"npx":"image/vnd.net-fpx",
1108 	"flx":"text/vnd.fmi.flexstor",
1109 	"fli":"video/x-fli",
1110 	"ftc":"application/vnd.fluxtime.clip",
1111 	"fdf":"application/vnd.fdf",
1112 	"f":"text/x-fortran",
1113 	"mif":"application/vnd.mif",
1114 	"fm":"application/vnd.framemaker",
1115 	"fh":"image/x-freehand",
1116 	"fsc":"application/vnd.fsc.weblaunch",
1117 	"fnc":"application/vnd.frogans.fnc",
1118 	"ltf":"application/vnd.frogans.ltf",
1119 	"ddd":"application/vnd.fujixerox.ddd",
1120 	"xdw":"application/vnd.fujixerox.docuworks",
1121 	"xbd":"application/vnd.fujixerox.docuworks.binder",
1122 	"oas":"application/vnd.fujitsu.oasys",
1123 	"oa2":"application/vnd.fujitsu.oasys2",
1124 	"oa3":"application/vnd.fujitsu.oasys3",
1125 	"fg5":"application/vnd.fujitsu.oasysgp",
1126 	"bh2":"application/vnd.fujitsu.oasysprs",
1127 	"spl":"application/x-futuresplash",
1128 	"fzs":"application/vnd.fuzzysheet",
1129 	"g3":"image/g3fax",
1130 	"gmx":"application/vnd.gmx",
1131 	"gtw":"model/vnd.gtw",
1132 	"txd":"application/vnd.genomatix.tuxedo",
1133 	"ggb":"application/vnd.geogebra.file",
1134 	"ggt":"application/vnd.geogebra.tool",
1135 	"gdl":"model/vnd.gdl",
1136 	"gex":"application/vnd.geometry-explorer",
1137 	"gxt":"application/vnd.geonext",
1138 	"g2w":"application/vnd.geoplan",
1139 	"g3w":"application/vnd.geospace",
1140 	"gsf":"application/x-font-ghostscript",
1141 	"bdf":"application/x-font-bdf",
1142 	"gtar":"application/x-gtar",
1143 	"texinfo":"application/x-texinfo",
1144 	"gnumeric":"application/x-gnumeric",
1145 	"kml":"application/vnd.google-earth.kml+xml",
1146 	"kmz":"application/vnd.google-earth.kmz",
1147 	"gqf":"application/vnd.grafeq",
1148 	"gif":"image/gif",
1149 	"gv":"text/vnd.graphviz",
1150 	"gac":"application/vnd.groove-account",
1151 	"ghf":"application/vnd.groove-help",
1152 	"gim":"application/vnd.groove-identity-message",
1153 	"grv":"application/vnd.groove-injector",
1154 	"gtm":"application/vnd.groove-tool-message",
1155 	"tpl":"application/vnd.groove-tool-template",
1156 	"vcg":"application/vnd.groove-vcard",
1157 	"h261":"video/h261",
1158 	"h263":"video/h263",
1159 	"h264":"video/h264",
1160 	"hpid":"application/vnd.hp-hpid",
1161 	"hps":"application/vnd.hp-hps",
1162 	"hdf":"application/x-hdf",
1163 	"rip":"audio/vnd.rip",
1164 	"hbci":"application/vnd.hbci",
1165 	"jlt":"application/vnd.hp-jlyt",
1166 	"pcl":"application/vnd.hp-pcl",
1167 	"hpgl":"application/vnd.hp-hpgl",
1168 	"hvs":"application/vnd.yamaha.hv-script",
1169 	"hvd":"application/vnd.yamaha.hv-dic",
1170 	"hvp":"application/vnd.yamaha.hv-voice",
1171 	"sfd-hdstx":"application/vnd.hydrostatix.sof-data",
1172 	"stk":"application/hyperstudio",
1173 	"hal":"application/vnd.hal+xml",
1174 	"html":"text/html",
1175 	"irm":"application/vnd.ibm.rights-management",
1176 	"sc":"application/vnd.ibm.secure-container",
1177 	"ics":"text/calendar",
1178 	"icc":"application/vnd.iccprofile",
1179 	"ico":"image/x-icon",
1180 	"icns":"image/x-icon",
1181 	"cur":"image/x-icon",
1182 	"igl":"application/vnd.igloader",
1183 	"ief":"image/ief",
1184 	"ivp":"application/vnd.immervision-ivp",
1185 	"ivu":"application/vnd.immervision-ivu",
1186 	"rif":"application/reginfo+xml",
1187 	"3dml":"text/vnd.in3d.3dml",
1188 	"spot":"text/vnd.in3d.spot",
1189 	"igs":"model/iges",
1190 	"i2g":"application/vnd.intergeo",
1191 	"cdy":"application/vnd.cinderella",
1192 	"xpw":"application/vnd.intercon.formnet",
1193 	"fcs":"application/vnd.isac.fcs",
1194 	"ipfix":"application/ipfix",
1195 	"cer":"application/pkix-cert",
1196 	"pki":"application/pkixcmp",
1197 	"crl":"application/pkix-crl",
1198 	"pkipath":"application/pkix-pkipath",
1199 	"igm":"application/vnd.insors.igm",
1200 	"rcprofile":"application/vnd.ipunplugged.rcprofile",
1201 	"irp":"application/vnd.irepository.package+xml",
1202 	"jad":"text/vnd.sun.j2me.app-descriptor",
1203 	"jar":"application/java-archive",
1204 	"class":"application/java-vm",
1205 	"jnlp":"application/x-java-jnlp-file",
1206 	"ser":"application/java-serialized-object",
1207 	"java":"text/x-java-sourcejava",
1208 	"js":"application/javascript",
1209 	"json":"application/json",
1210 	"joda":"application/vnd.joost.joda-archive",
1211 	"jpm":"video/jpm",
1212 	"jpeg":"image/jpeg",
1213 	"jpe":"image/jpeg",
1214 	"jpg":"image/jpeg",
1215 	"pjpeg":"image/pjpeg",
1216 	"jpgv":"video/jpeg",
1217 	"ktz":"application/vnd.kahootz",
1218 	"mmd":"application/vnd.chipnuts.karaoke-mmd",
1219 	"karbon":"application/vnd.kde.karbon",
1220 	"chrt":"application/vnd.kde.kchart",
1221 	"kfo":"application/vnd.kde.kformula",
1222 	"flw":"application/vnd.kde.kivio",
1223 	"kon":"application/vnd.kde.kontour",
1224 	"kpr":"application/vnd.kde.kpresenter",
1225 	"ksp":"application/vnd.kde.kspread",
1226 	"kwd":"application/vnd.kde.kword",
1227 	"htke":"application/vnd.kenameaapp",
1228 	"kia":"application/vnd.kidspiration",
1229 	"kne":"application/vnd.kinar",
1230 	"sse":"application/vnd.kodak-descriptor",
1231 	"lasxml":"application/vnd.las.las+xml",
1232 	"latex":"application/x-latex",
1233 	"lbd":"application/vnd.llamagraphics.life-balance.desktop",
1234 	"lbe":"application/vnd.llamagraphics.life-balance.exchange+xml",
1235 	"jam":"application/vnd.jam",
1236 	"123":"application/vnd.lotus-1-2-3",
1237 	"apr":"application/vnd.lotus-approach",
1238 	"pre":"application/vnd.lotus-freelance",
1239 	"nsf":"application/vnd.lotus-notes",
1240 	"org":"application/vnd.lotus-organizer",
1241 	"scm":"application/vnd.lotus-screencam",
1242 	"lwp":"application/vnd.lotus-wordpro",
1243 	"lvp":"audio/vnd.lucent.voice",
1244 	"m3u":"audio/x-mpegurl",
1245 	"m4v":"video/x-m4v",
1246 	"hqx":"application/mac-binhex40",
1247 	"portpkg":"application/vnd.macports.portpkg",
1248 	"mgp":"application/vnd.osgeo.mapguide.package",
1249 	"mrc":"application/marc",
1250 	"mrcx":"application/marcxml+xml",
1251 	"mxf":"application/mxf",
1252 	"nbp":"application/vnd.wolfram.player",
1253 	"ma":"application/mathematica",
1254 	"mathml":"application/mathml+xml",
1255 	"mbox":"application/mbox",
1256 	"mc1":"application/vnd.medcalcdata",
1257 	"mscml":"application/mediaservercontrol+xml",
1258 	"cdkey":"application/vnd.mediastation.cdkey",
1259 	"mwf":"application/vnd.mfer",
1260 	"mfm":"application/vnd.mfmp",
1261 	"msh":"model/mesh",
1262 	"mads":"application/mads+xml",
1263 	"mets":"application/mets+xml",
1264 	"mods":"application/mods+xml",
1265 	"meta4":"application/metalink4+xml",
1266 	"mcd":"application/vnd.mcd",
1267 	"flo":"application/vnd.micrografx.flo",
1268 	"igx":"application/vnd.micrografx.igx",
1269 	"es3":"application/vnd.eszigno3+xml",
1270 	"mdb":"application/x-msaccess",
1271 	"asf":"video/x-ms-asf",
1272 	"exe":"application/x-msdownload",
1273 	"cil":"application/vnd.ms-artgalry",
1274 	"cab":"application/vnd.ms-cab-compressed",
1275 	"ims":"application/vnd.ms-ims",
1276 	"application":"application/x-ms-application",
1277 	"clp":"application/x-msclip",
1278 	"mdi":"image/vnd.ms-modi",
1279 	"eot":"application/vnd.ms-fontobject",
1280 	"xls":"application/ms-excel",
1281 	"xlam":"application/vnd.ms-excel.addin.macroenabled.12",
1282 	"xlsb":"application/vnd.ms-excel.sheet.binary.macroenabled.12",
1283 	"xltm":"application/vnd.ms-excel.template.macroenabled.12",
1284 	"xlsm":"application/vnd.ms-excel.sheet.macroenabled.12",
1285 	"chm":"application/vnd.ms-htmlhelp",
1286 	"crd":"application/x-mscardfile",
1287 	"lrm":"application/vnd.ms-lrm",
1288 	"mvb":"application/x-msmediaview",
1289 	"mny":"application/x-msmoney",
1290 	"pptx":"application/vnd.openxmlformats-officedocument.presentationml.presentation",
1291 	"sldx":"application/vnd.openxmlformats-officedocument.presentationml.slide",
1292 	"ppsx":"application/vnd.openxmlformats-officedocument.presentationml.slideshow",
1293 	"potx":"application/vnd.openxmlformats-officedocument.presentationml.template",
1294 	"xlsx":"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
1295 	"xltx":"application/vnd.openxmlformats-officedocument.spreadsheetml.template",
1296 	"docx":"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
1297 	"dotx":"application/vnd.openxmlformats-officedocument.wordprocessingml.template",
1298 	"obd":"application/x-msbinder",
1299 	"thmx":"application/vnd.ms-officetheme",
1300 	"onetoc":"application/onenote",
1301 	"pya":"audio/vnd.ms-playready.media.pya",
1302 	"pyv":"video/vnd.ms-playready.media.pyv",
1303 	"ppt":"application/ms-powerpoint",
1304 	"pps":"application/ms-powerpoint",
1305 	"ppam":"application/vnd.ms-powerpoint.addin.macroenabled.12",
1306 	"sldm":"application/vnd.ms-powerpoint.slide.macroenabled.12",
1307 	"pptm":"application/vnd.ms-powerpoint.presentation.macroenabled.12",
1308 	"ppsm":"application/vnd.ms-powerpoint.slideshow.macroenabled.12",
1309 	"potm":"application/vnd.ms-powerpoint.template.macroenabled.12",
1310 	"mpp":"application/vnd.ms-project",
1311 	"pub":"application/x-mspublisher",
1312 	"scd":"application/x-msschedule",
1313 	"xap":"application/x-silverlight-app",
1314 	"stl":"application/vnd.ms-pki.stl",
1315 	"cat":"application/vnd.ms-pki.seccat",
1316 	"vsd":"application/vnd.visio",
1317 	"vsdx":"application/vnd.visio2013",
1318 	"wm":"video/x-ms-wm",
1319 	"wma":"audio/x-ms-wma",
1320 	"wax":"audio/x-ms-wax",
1321 	"wmx":"video/x-ms-wmx",
1322 	"wmd":"application/x-ms-wmd",
1323 	"wpl":"application/vnd.ms-wpl",
1324 	"wmz":"application/x-ms-wmz",
1325 	"wmv":"video/x-ms-wmv",
1326 	"wvx":"video/x-ms-wvx",
1327 	"wmf":"application/x-msmetafile",
1328 	"trm":"application/x-msterminal",
1329 	"doc":"application/msword",
1330 	"docm":"application/vnd.ms-word.document.macroenabled.12",
1331 	"dotm":"application/vnd.ms-word.template.macroenabled.12",
1332 	"wri":"application/x-mswrite",
1333 	"wps":"application/vnd.ms-works",
1334 	"xbap":"application/x-ms-xbap",
1335 	"xps":"application/vnd.ms-xpsdocument",
1336 	"mid":"audio/midi",
1337 	"mpy":"application/vnd.ibm.minipay",
1338 	"afp":"application/vnd.ibm.modcap",
1339 	"rms":"application/vnd.jcp.javame.midlet-rms",
1340 	"tmo":"application/vnd.tmobile-livetv",
1341 	"prc":"application/x-mobipocket-ebook",
1342 	"mbk":"application/vnd.mobius.mbk",
1343 	"dis":"application/vnd.mobius.dis",
1344 	"plc":"application/vnd.mobius.plc",
1345 	"mqy":"application/vnd.mobius.mqy",
1346 	"msl":"application/vnd.mobius.msl",
1347 	"txf":"application/vnd.mobius.txf",
1348 	"daf":"application/vnd.mobius.daf",
1349 	"fly":"text/vnd.fly",
1350 	"mpc":"application/vnd.mophun.certificate",
1351 	"mpn":"application/vnd.mophun.application",
1352 	"mj2":"video/mj2",
1353 	"mpga":"audio/mpeg",
1354 	"mxu":"video/vnd.mpegurl",
1355 	"mpeg":"video/mpeg",
1356 	"mpg":"video/mpeg",
1357 	"m21":"application/mp21",
1358 	"mp4a":"audio/mp4",
1359 	"mp4":"video/mp4",
1360 	"m4a":"video/mp4",
1361 	"m4b":"video/mp4",
1362 	"m4r":"video/mp4",
1363 	"m4v":"video/mp4",
1364 	"m3u8":"application/vnd.apple.mpegurl",
1365 	"mus":"application/vnd.musician",
1366 	"msty":"application/vnd.muvee.style",
1367 	"mxml":"application/xv+xml",
1368 	"ngdat":"application/vnd.nokia.n-gage.data",
1369 	"n-gage":"application/vnd.nokia.n-gage.symbian.install",
1370 	"ncx":"application/x-dtbncx+xml",
1371 	"nc":"application/x-netcdf",
1372 	"nlu":"application/vnd.neurolanguage.nlu",
1373 	"dna":"application/vnd.dna",
1374 	"nnd":"application/vnd.noblenet-directory",
1375 	"nns":"application/vnd.noblenet-sealer",
1376 	"nnw":"application/vnd.noblenet-web",
1377 	"rpst":"application/vnd.nokia.radio-preset",
1378 	"rpss":"application/vnd.nokia.radio-presets",
1379 	"n3":"text/n3",
1380 	"edm":"application/vnd.novadigm.edm",
1381 	"edx":"application/vnd.novadigm.edx",
1382 	"ext":"application/vnd.novadigm.ext",
1383 	"gph":"application/vnd.flographit",
1384 	"ecelp4800":"audio/vnd.nuera.ecelp4800",
1385 	"ecelp7470":"audio/vnd.nuera.ecelp7470",
1386 	"ecelp9600":"audio/vnd.nuera.ecelp9600",
1387 	"oda":"application/oda",
1388 	"ogx":"application/ogg",
1389 	"oga":"audio/ogg",
1390 	"ogv":"video/ogg",
1391 	"ogg":"video/ogg",
1392 	"dd2":"application/vnd.oma.dd2+xml",
1393 	"oth":"application/vnd.oasis.opendocument.text-web",
1394 	"opf":"application/oebps-package+xml",
1395 	"qbo":"application/vnd.intu.qbo",
1396 	"oxt":"application/vnd.openofficeorg.extension",
1397 	"osf":"application/vnd.yamaha.openscoreformat",
1398 	"weba":"audio/webm",
1399 	"webm":"video/webm",
1400 	"odc":"application/vnd.oasis.opendocument.chart",
1401 	"otc":"application/vnd.oasis.opendocument.chart-template",
1402 	"odb":"application/vnd.oasis.opendocument.database",
1403 	"odf":"application/vnd.oasis.opendocument.formula",
1404 	"odft":"application/vnd.oasis.opendocument.formula-template",
1405 	"odg":"application/vnd.oasis.opendocument.graphics",
1406 	"otg":"application/vnd.oasis.opendocument.graphics-template",
1407 	"odi":"application/vnd.oasis.opendocument.image",
1408 	"oti":"application/vnd.oasis.opendocument.image-template",
1409 	"odp":"application/vnd.oasis.opendocument.presentation",
1410 	"otp":"application/vnd.oasis.opendocument.presentation-template",
1411 	"ods":"application/vnd.oasis.opendocument.spreadsheet",
1412 	"ots":"application/vnd.oasis.opendocument.spreadsheet-template",
1413 	"odt":"application/vnd.oasis.opendocument.text",
1414 	"odm":"application/vnd.oasis.opendocument.text-master",
1415 	"ott":"application/vnd.oasis.opendocument.text-template",
1416 	"ktx":"image/ktx",
1417 	"sxc":"application/vnd.sun.xml.calc",
1418 	"stc":"application/vnd.sun.xml.calc.template",
1419 	"sxd":"application/vnd.sun.xml.draw",
1420 	"std":"application/vnd.sun.xml.draw.template",
1421 	"sxi":"application/vnd.sun.xml.impress",
1422 	"sti":"application/vnd.sun.xml.impress.template",
1423 	"sxm":"application/vnd.sun.xml.math",
1424 	"sxw":"application/vnd.sun.xml.writer",
1425 	"sxg":"application/vnd.sun.xml.writer.global",
1426 	"stw":"application/vnd.sun.xml.writer.template",
1427 	"otf":"application/x-font-otf",
1428 	"osfpvg":"application/vnd.yamaha.openscoreformat.osfpvg+xml",
1429 	"dp":"application/vnd.osgi.dp",
1430 	"pdb":"application/vnd.palm",
1431 	"p":"text/x-pascal",
1432 	"paw":"application/vnd.pawaafile",
1433 	"pclxl":"application/vnd.hp-pclxl",
1434 	"efif":"application/vnd.picsel",
1435 	"pcx":"image/x-pcx",
1436 	"psd":"image/vnd.adobe.photoshop",
1437 	"prf":"application/pics-rules",
1438 	"pic":"image/x-pict",
1439 	"chat":"application/x-chat",
1440 	"p10":"application/pkcs10",
1441 	"p12":"application/x-pkcs12",
1442 	"p7m":"application/pkcs7-mime",
1443 	"p7s":"application/pkcs7-signature",
1444 	"p7r":"application/x-pkcs7-certreqresp",
1445 	"p7b":"application/x-pkcs7-certificates",
1446 	"p8":"application/pkcs8",
1447 	"plf":"application/vnd.pocketlearn",
1448 	"pnm":"image/x-portable-anymap",
1449 	"pbm":"image/x-portable-bitmap",
1450 	"pcf":"application/x-font-pcf",
1451 	"pfr":"application/font-tdpfr",
1452 	"pgn":"application/x-chess-pgn",
1453 	"pgm":"image/x-portable-graymap",
1454 	"png":"image/png",
1455 	"ppm":"image/x-portable-pixmap",
1456 	"pskcxml":"application/pskc+xml",
1457 	"pml":"application/vnd.ctc-posml",
1458 	"ai":"application/postscript",
1459 	"pfa":"application/x-font-type1",
1460 	"pbd":"application/vnd.powerbuilder6",
1461 	"pgp":"application/pgp-encrypted",
1462 	"box":"application/vnd.previewsystems.box",
1463 	"ptid":"application/vnd.pvi.ptid1",
1464 	"pls":"application/pls+xml",
1465 	"str":"application/vnd.pg.format",
1466 	"ei6":"application/vnd.pg.osasli",
1467 	"dsc":"text/prs.lines.tag",
1468 	"psf":"application/x-font-linux-psf",
1469 	"qps":"application/vnd.publishare-delta-tree",
1470 	"wg":"application/vnd.pmi.widget",
1471 	"qxd":"application/vnd.quark.quarkxpress",
1472 	"esf":"application/vnd.epson.esf",
1473 	"msf":"application/vnd.epson.msf",
1474 	"ssf":"application/vnd.epson.ssf",
1475 	"qam":"application/vnd.epson.quickanime",
1476 	"qfx":"application/vnd.intu.qfx",
1477 	"qt":"video/quicktime",
1478 	"rar":"application/x-rar-compressed",
1479 	"ram":"audio/x-pn-realaudio",
1480 	"rmp":"audio/x-pn-realaudio-plugin",
1481 	"rsd":"application/rsd+xml",
1482 	"rm":"application/vnd.rn-realmedia",
1483 	"ra":"application/vnd.rn-realmedia",
1484 	"rv":"application/vnd.rn-realmedia",
1485 	"bed":"application/vnd.realvnc.bed",
1486 	"mxl":"application/vnd.recordare.musicxml",
1487 	"musicxml":"application/vnd.recordare.musicxml+xml",
1488 	"rnc":"application/relax-ng-compact-syntax",
1489 	"rdz":"application/vnd.data-vision.rdz",
1490 	"rdf":"application/rdf+xml",
1491 	"rp9":"application/vnd.cloanto.rp9",
1492 	"jisp":"application/vnd.jisp",
1493 	"rtf":"application/rtf",
1494 	"rtx":"text/richtext",
1495 	"link66":"application/vnd.route66.link66+xml",
1496 	"rss":"application/rss+xml",
1497 	"shf":"application/shf+xml",
1498 	"st":"application/vnd.sailingtracker.track",
1499 	"svg":"image/svg+xml",
1500 	"svgz":"image/svg+xml",
1501 	"sus":"application/vnd.sus-calendar",
1502 	"sru":"application/sru+xml",
1503 	"setpay":"application/set-payment-initiation",
1504 	"setreg":"application/set-registration-initiation",
1505 	"sema":"application/vnd.sema",
1506 	"semd":"application/vnd.semd",
1507 	"semf":"application/vnd.semf",
1508 	"see":"application/vnd.seemail",
1509 	"snf":"application/x-font-snf",
1510 	"spq":"application/scvp-vp-request",
1511 	"spp":"application/scvp-vp-response",
1512 	"scq":"application/scvp-cv-request",
1513 	"scs":"application/scvp-cv-response",
1514 	"sdp":"application/sdp",
1515 	"etx":"text/x-setext",
1516 	"movie":"video/x-sgi-movie",
1517 	"ifm":"application/vnd.shana.informed.formdata",
1518 	"itp":"application/vnd.shana.informed.formtemplate",
1519 	"iif":"application/vnd.shana.informed.interchange",
1520 	"ipk":"application/vnd.shana.informed.package",
1521 	"tfi":"application/thraud+xml",
1522 	"shar":"application/x-shar",
1523 	"rgb":"image/x-rgb",
1524 	"slt":"application/vnd.epson.salt",
1525 	"aso":"application/vnd.accpac.simply.aso",
1526 	"imp":"application/vnd.accpac.simply.imp",
1527 	"twd":"application/vnd.simtech-mindmapper",
1528 	"csp":"application/vnd.commonspace",
1529 	"saf":"application/vnd.yamaha.smaf-audio",
1530 	"mmf":"application/vnd.smaf",
1531 	"spf":"application/vnd.yamaha.smaf-phrase",
1532 	"teacher":"application/vnd.smart.teacher",
1533 	"svd":"application/vnd.svd",
1534 	"rq":"application/sparql-query",
1535 	"srx":"application/sparql-results+xml",
1536 	"gram":"application/srgs",
1537 	"grxml":"application/srgs+xml",
1538 	"ssml":"application/ssml+xml",
1539 	"skp":"application/vnd.koan",
1540 	"sgml":"text/sgml",
1541 	"sdc":"application/vnd.stardivision.calc",
1542 	"sda":"application/vnd.stardivision.draw",
1543 	"sdd":"application/vnd.stardivision.impress",
1544 	"smf":"application/vnd.stardivision.math",
1545 	"sdw":"application/vnd.stardivision.writer",
1546 	"sgl":"application/vnd.stardivision.writer-global",
1547 	"sm":"application/vnd.stepmania.stepchart",
1548 	"sit":"application/x-stuffit",
1549 	"sitx":"application/x-stuffitx",
1550 	"sdkm":"application/vnd.solent.sdkm+xml",
1551 	"xo":"application/vnd.olpc-sugar",
1552 	"au":"audio/basic",
1553 	"wqd":"application/vnd.wqd",
1554 	"sis":"application/vnd.symbian.install",
1555 	"smi":"application/smil+xml",
1556 	"xsm":"application/vnd.syncml+xml",
1557 	"bdm":"application/vnd.syncml.dm+wbxml",
1558 	"xdm":"application/vnd.syncml.dm+xml",
1559 	"sv4cpio":"application/x-sv4cpio",
1560 	"sv4crc":"application/x-sv4crc",
1561 	"sbml":"application/sbml+xml",
1562 	"tsv":"text/tab-separated-values",
1563 	"tif":"image/tiff",
1564 	"tiff":"image/tiff",
1565 	"tao":"application/vnd.tao.intent-module-archive",
1566 	"tar":"application/x-tar",
1567 	"tcl":"application/x-tcl",
1568 	"tex":"application/x-tex",
1569 	"tfm":"application/x-tex-tfm",
1570 	"tei":"application/tei+xml",
1571 	"txt":"text/plain",
1572 	"dxp":"application/vnd.spotfire.dxp",
1573 	"sfs":"application/vnd.spotfire.sfs",
1574 	"tsd":"application/timestamped-data",
1575 	"tpt":"application/vnd.trid.tpt",
1576 	"mxs":"application/vnd.triscape.mxs",
1577 	"t":"text/troff",
1578 	"tra":"application/vnd.trueapp",
1579 	"ttf":"application/x-font-ttf",
1580 	"ttl":"text/turtle",
1581 	"umj":"application/vnd.umajin",
1582 	"uoml":"application/vnd.uoml+xml",
1583 	"unityweb":"application/vnd.unity",
1584 	"ufd":"application/vnd.ufdl",
1585 	"uri":"text/uri-list",
1586 	"utz":"application/vnd.uiq.theme",
1587 	"ustar":"application/x-ustar",
1588 	"uu":"text/x-uuencode",
1589 	"vcs":"text/x-vcalendar",
1590 	"vcf":"text/x-vcard",
1591 	"vcd":"application/x-cdlink",
1592 	"vsf":"application/vnd.vsf",
1593 	"wrl":"model/vrml",
1594 	"vcx":"application/vnd.vcx",
1595 	"mts":"model/vnd.mts",
1596 	"vtu":"model/vnd.vtu",
1597 	"vis":"application/vnd.visionary",
1598 	"viv":"video/vnd.vivo",
1599 	"ccxml":"application/ccxml+xml",
1600 	"vxml":"application/voicexml+xml",
1601 	"src":"application/x-wais-source",
1602 	"wbxml":"application/vnd.wap.wbxml",
1603 	"wbmp":"image/vnd.wap.wbmp",
1604 	"wav":"audio/x-wav",
1605 	"davmount":"application/davmount+xml",
1606 	"woff":"application/x-font-woff",
1607 	"wspolicy":"application/wspolicy+xml",
1608 	"webp":"image/webp",
1609 	"wtb":"application/vnd.webturbo",
1610 	"wgt":"application/widget",
1611 	"hlp":"application/winhlp",
1612 	"wml":"text/vnd.wap.wml",
1613 	"wmls":"text/vnd.wap.wmlscript",
1614 	"wmlsc":"application/vnd.wap.wmlscriptc",
1615 	"wpd":"application/vnd.wordperfect",
1616 	"stf":"application/vnd.wt.stf",
1617 	"wsdl":"application/wsdl+xml",
1618 	"xbm":"image/x-xbitmap",
1619 	"xpm":"image/x-xpixmap",
1620 	"xwd":"image/x-xwindowdump",
1621 	"der":"application/x-x509-ca-cert",
1622 	"fig":"application/x-xfig",
1623 	"xhtml":"application/xhtml+xml",
1624 	"xdf":"application/xcap-diff+xml",
1625 	"xenc":"application/xenc+xml",
1626 	"xer":"application/patch-ops-error+xml",
1627 	"rl":"application/resource-lists+xml",
1628 	"rs":"application/rls-services+xml",
1629 	"rld":"application/resource-lists-diff+xml",
1630 	"xslt":"application/xslt+xml",
1631 	"xop":"application/xop+xml",
1632 	"xpi":"application/x-xpinstall",
1633 	"xspf":"application/xspf+xml",
1634 	"xul":"application/vnd.mozilla.xul+xml",
1635 	"xyz":"chemical/x-xyz",
1636 	"yaml":"text/yaml",
1637 	"yang":"application/yang",
1638 	"yin":"application/yin+xml",
1639 	"zir":"application/vnd.zul",
1640 	"zip":"application/zip",
1641 	"zmm":"application/vnd.handheld-entertainment+xml",
1642 	"zaz":"application/vnd.zzazz.deck+xml",
1643 	"xmp":"application/octet-stream",
1644 	"mov":"video/quicktime",
1645 	"ini":"text/plain",
1646 	"mp3":"audio/x-mpeg"
1647 };
1648