text: define([], function() {
  
  	/* FileSaver.js
  	 * A saveAs() FileSaver implementation.
  	 * 2013-01-23
  	 *
  	 * By Eli Grey, http://eligrey.com
  	 * License: X11/MIT
  	 *   See LICENSE.md
  	 */
  
  	/*global self */
  	/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
  	  plusplus: true */
  
  	/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
  
  	var saveAs = saveAs
  	  || (navigator.msSaveBlob && navigator.msSaveBlob.bind(navigator))
  	  || (function(view) {
  		"use strict";
  		var
  			  doc = view.document
  			  // only get URL when necessary in case BlobBuilder.js hasn't overridden it yet
  			, get_URL = function() {
  				return view.URL || view.webkitURL || view;
  			}
  			, URL = view.URL || view.webkitURL || view
  			, save_link = function() {
                              try {
                                  return doc.createElementNS("http://www.w3.org/1999/xhtml", "a");
                              } catch( e ) {
                                  return doc.createElement('a');
                              }
                          }.call(this)
  			, can_use_save_link = "download" in save_link
  			, click = function(node) {
  				var event = doc.createEvent("MouseEvents");
  				event.initMouseEvent(
  					"click", true, false, view, 0, 0, 0, 0, 0
  					, false, false, false, false, 0, null
  				);
  				node.dispatchEvent(event);
  			}
  			, webkit_req_fs = view.webkitRequestFileSystem
  			, req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem
  			, throw_outside = function (ex) {
  				(view.setImmediate || view.setTimeout)(function() {
  					throw ex;
  				}, 0);
  			}
  			, force_saveable_type = "application/octet-stream"
  			, fs_min_size = 0
  			, deletion_queue = []
  			, process_deletion_queue = function() {
  				var i = deletion_queue.length;
  				while (i--) {
  					var file = deletion_queue[i];
  					if (typeof file === "string") { // file is an object URL
  						URL.revokeObjectURL(file);
  					} else { // file is a File
  						file.remove();
  					}
  				}
  				deletion_queue.length = 0; // clear queue
  			}
  			, dispatch = function(filesaver, event_types, event) {
  				event_types = [].concat(event_types);
  				var i = event_types.length;
  				while (i--) {
  					var listener = filesaver["on" + event_types[i]];
  					if (typeof listener === "function") {
  						try {
  							listener.call(filesaver, event || filesaver);
  						} catch (ex) {
  							throw_outside(ex);
  						}
  					}
  				}
  			}
  			, FileSaver = function(blob, name) {
  				// First try a.download, then web filesystem, then object URLs
  				var
  					  filesaver = this
  					, type = blob.type
  					, blob_changed = false
  					, object_url
  					, target_view
  					, get_object_url = function() {
  						var object_url = get_URL().createObjectURL(blob);
  						deletion_queue.push(object_url);
  						return object_url;
  					}
  					, dispatch_all = function() {
  						dispatch(filesaver, "writestart progress write writeend".split(" "));
  					}
  					// on any filesys errors revert to saving with object URLs
  					, fs_error = function() {
  						// don't create more object URLs than needed
  						if (blob_changed || !object_url) {
  							object_url = get_object_url(blob);
  						}
  						if (target_view) {
  							target_view.location.href = object_url;
  						} else {
  	                        window.open(object_url, "_blank");
  	                    }
  						filesaver.readyState = filesaver.DONE;
  						dispatch_all();
  					}
  					, abortable = function(func) {
  						return function() {
  							if (filesaver.readyState !== filesaver.DONE) {
  								return func.apply(this, arguments);
  							}
  						};
  					}
  					, create_if_not_found = {create: true, exclusive: false}
  					, slice
  				;
  				filesaver.readyState = filesaver.INIT;
  				if (!name) {
  					name = "download";
  				}
  				if (can_use_save_link) {
  					object_url = get_object_url(blob);
  					save_link.href = object_url;
  					save_link.download = name;
  					click(save_link);
  					filesaver.readyState = filesaver.DONE;
  					dispatch_all();
  					return;
  				}
  				// Object and web filesystem URLs have a problem saving in Google Chrome when
  				// viewed in a tab, so I force save with application/octet-stream
  				// http://code.google.com/p/chromium/issues/detail?id=91158
  				if (view.chrome && type && type !== force_saveable_type) {
  					slice = blob.slice || blob.webkitSlice;
  					blob = slice.call(blob, 0, blob.size, force_saveable_type);
  					blob_changed = true;
  				}
  				// Since I can't be sure that the guessed media type will trigger a download
  				// in WebKit, I append .download to the filename.
  				// https://bugs.webkit.org/show_bug.cgi?id=65440
  				if (webkit_req_fs && name !== "download") {
  					name += ".download";
  				}
  				if (type === force_saveable_type || webkit_req_fs) {
  					target_view = view;
  				}
  				if (!req_fs) {
  					fs_error();
  					return;
  				}
  				fs_min_size += blob.size;
  				req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) {
  					fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) {
  						var save = function() {
  							dir.getFile(name, create_if_not_found, abortable(function(file) {
  								file.createWriter(abortable(function(writer) {
  									writer.onwriteend = function(event) {
  										target_view.location.href = file.toURL();
  										deletion_queue.push(file);
  										filesaver.readyState = filesaver.DONE;
  										dispatch(filesaver, "writeend", event);
  									};
  									writer.onerror = function() {
  										var error = writer.error;
  										if (error.code !== error.ABORT_ERR) {
  											fs_error();
  										}
  									};
  									"writestart progress write abort".split(" ").forEach(function(event) {
  										writer["on" + event] = filesaver["on" + event];
  									});
  									writer.write(blob);
  									filesaver.abort = function() {
  										writer.abort();
  										filesaver.readyState = filesaver.DONE;
  									};
  									filesaver.readyState = filesaver.WRITING;
  								}), fs_error);
  							}), fs_error);
  						};
  						dir.getFile(name, {create: false}, abortable(function(file) {
  							// delete file if it already exists
  							file.remove();
  							save();
  						}), abortable(function(ex) {
  							if (ex.code === ex.NOT_FOUND_ERR) {
  								save();
  							} else {
  								fs_error();
  							}
  						}));
  					}), fs_error);
  				}), fs_error);
  			}
  			, FS_proto = FileSaver.prototype
  			, saveAs = function(blob, name) {
  				return new FileSaver(blob, name);
  			}
  		;
  		FS_proto.abort = function() {
  			var filesaver = this;
  			filesaver.readyState = filesaver.DONE;
  			dispatch(filesaver, "abort");
  		};
  		FS_proto.readyState = FS_proto.INIT = 0;
  		FS_proto.WRITING = 1;
  		FS_proto.DONE = 2;
  
  		FS_proto.error =
  		FS_proto.onwritestart =
  		FS_proto.onprogress =
  		FS_proto.onwrite =
  		FS_proto.onabort =
  		FS_proto.onerror =
  		FS_proto.onwriteend =
  			null;
  
                  try {
  		    view.addEventListener("unload", process_deletion_queue, false);
                  } catch(e) {
                      console.warn('FileSaver.js probably will not work');
                  }
  		return saveAs;
  	}(self));
  
  	return saveAs;
  });
  