text: /*
   * jQuery File Upload AngularJS Plugin 2.2.0
   * https://github.com/blueimp/jQuery-File-Upload
   *
   * Copyright 2013, Sebastian Tschan
   * https://blueimp.net
   *
   * Licensed under the MIT license:
   * http://www.opensource.org/licenses/MIT
   */
  
  /* jshint nomen:false */
  /* global define, angular */
  
  (function (factory) {
      'use strict';
      if (typeof define === 'function' && define.amd) {
          // Register as an anonymous AMD module:
          define([
              'jquery',
              'angular',
              './jquery.fileupload-image',
              './jquery.fileupload-audio',
              './jquery.fileupload-video',
              './jquery.fileupload-validate'
          ], factory);
      } else {
          factory();
      }
  }(function () {
      'use strict';
  
      angular.module('blueimp.fileupload', [])
  
          // The fileUpload service provides configuration options
          // for the fileUpload directive and default handlers for
          // File Upload events:
          .provider('fileUpload', function () {
              var scopeEvalAsync = function (expression) {
                      var scope = angular.element(this)
                          .fileupload('option', 'scope');
                      // Schedule a new $digest cycle if not already inside of one
                      // and evaluate the given expression:
                      scope.$evalAsync(expression);
                  },
                  addFileMethods = function (scope, data) {
                      var files = data.files,
                          file = files[0];
                      angular.forEach(files, function (file, index) {
                          file._index = index;
                          file.$state = function () {
                              return data.state();
                          };
                          file.$processing = function () {
                              return data.processing();
                          };
                          file.$progress = function () {
                              return data.progress();
                          };
                          file.$response = function () {
                              return data.response();
                          };
                      });
                      file.$submit = function () {
                          if (!file.error) {
                              return data.submit();
                          }
                      };
                      file.$cancel = function () {
                          return data.abort();
                      };
                  },
                  $config;
              $config = this.defaults = {
                  handleResponse: function (e, data) {
                      var files = data.result && data.result.files;
                      if (files) {
                          data.scope.replace(data.files, files);
                      } else if (data.errorThrown ||
                          data.textStatus === 'error') {
                          data.files[0].error = data.errorThrown ||
                          data.textStatus;
                      }
                  },
                  add: function (e, data) {
                      if (e.isDefaultPrevented()) {
                          return false;
                      }
                      var scope = data.scope,
                          filesCopy = [];
                      angular.forEach(data.files, function (file) {
                          filesCopy.push(file);
                      });
                      scope.$apply(function () {
                          addFileMethods(scope, data);
                          var method = scope.option('prependFiles') ?
                              'unshift' : 'push';
                          Array.prototype[method].apply(scope.queue, data.files);
                      });
                      data.process(function () {
                          return scope.process(data);
                      }).always(function () {
                          scope.$apply(function () {
                              addFileMethods(scope, data);
                              scope.replace(filesCopy, data.files);
                          });
                      }).then(function () {
                          if ((scope.option('autoUpload') ||
                              data.autoUpload) &&
                              data.autoUpload !== false) {
                              data.submit();
                          }
                      });
                  },
                  progress: function (e, data) {
                      if (e.isDefaultPrevented()) {
                          return false;
                      }
                      data.scope.$apply();
                  },
                  done: function (e, data) {
                      if (e.isDefaultPrevented()) {
                          return false;
                      }
                      var that = this;
                      data.scope.$apply(function () {
                          data.handleResponse.call(that, e, data);
                      });
                  },
                  fail: function (e, data) {
                      if (e.isDefaultPrevented()) {
                          return false;
                      }
                      var that = this,
                          scope = data.scope;
                      if (data.errorThrown === 'abort') {
                          scope.clear(data.files);
                          return;
                      }
                      scope.$apply(function () {
                          data.handleResponse.call(that, e, data);
                      });
                  },
                  stop: scopeEvalAsync,
                  processstart: scopeEvalAsync,
                  processstop: scopeEvalAsync,
                  getNumberOfFiles: function () {
                      var scope = this.scope;
                      return scope.queue.length - scope.processing();
                  },
                  dataType: 'json',
                  autoUpload: false
              };
              this.$get = [
                  function () {
                      return {
                          defaults: $config
                      };
                  }
              ];
          })
  
          // Format byte numbers to readable presentations:
          .provider('formatFileSizeFilter', function () {
              var $config = {
                  // Byte units following the IEC format
                  // http://en.wikipedia.org/wiki/Kilobyte
                  units: [
                      {size: 1000000000, suffix: ' GB'},
                      {size: 1000000, suffix: ' MB'},
                      {size: 1000, suffix: ' KB'}
                  ]
              };
              this.defaults = $config;
              this.$get = function () {
                  return function (bytes) {
                      if (!angular.isNumber(bytes)) {
                          return '';
                      }
                      var unit = true,
                          i = 0,
                          prefix,
                          suffix;
                      while (unit) {
                          unit = $config.units[i];
                          prefix = unit.prefix || '';
                          suffix = unit.suffix || '';
                          if (i === $config.units.length - 1 || bytes >= unit.size) {
                              return prefix + (bytes / unit.size).toFixed(2) + suffix;
                          }
                          i += 1;
                      }
                  };
              };
          })
  
          // The FileUploadController initializes the fileupload widget and
          // provides scope methods to control the File Upload functionality:
          .controller('FileUploadController', [
              '$scope', '$element', '$attrs', '$window', 'fileUpload',
              function ($scope, $element, $attrs, $window, fileUpload) {
                  var uploadMethods = {
                      progress: function () {
                          return $element.fileupload('progress');
                      },
                      active: function () {
                          return $element.fileupload('active');
                      },
                      option: function (option, data) {
                          if (arguments.length === 1) {
                              return $element.fileupload('option', option);
                          }
                          $element.fileupload('option', option, data);
                      },
                      add: function (data) {
                          return $element.fileupload('add', data);
                      },
                      send: function (data) {
                          return $element.fileupload('send', data);
                      },
                      process: function (data) {
                          return $element.fileupload('process', data);
                      },
                      processing: function (data) {
                          return $element.fileupload('processing', data);
                      }
                  };
                  $scope.disabled = !$window.jQuery.support.fileInput;
                  $scope.queue = $scope.queue || [];
                  $scope.clear = function (files) {
                      var queue = this.queue,
                          i = queue.length,
                          file = files,
                          length = 1;
                      if (angular.isArray(files)) {
                          file = files[0];
                          length = files.length;
                      }
                      while (i) {
                          i -= 1;
                          if (queue[i] === file) {
                              return queue.splice(i, length);
                          }
                      }
                  };
                  $scope.replace = function (oldFiles, newFiles) {
                      var queue = this.queue,
                          file = oldFiles[0],
                          i,
                          j;
                      for (i = 0; i < queue.length; i += 1) {
                          if (queue[i] === file) {
                              for (j = 0; j < newFiles.length; j += 1) {
                                  queue[i + j] = newFiles[j];
                              }
                              return;
                          }
                      }
                  };
                  $scope.applyOnQueue = function (method) {
                      var list = this.queue.slice(0),
                          i,
                          file;
                      for (i = 0; i < list.length; i += 1) {
                          file = list[i];
                          if (file[method]) {
                              file[method]();
                          }
                      }
                  };
                  $scope.submit = function () {
                      this.applyOnQueue('$submit');
                  };
                  $scope.cancel = function () {
                      this.applyOnQueue('$cancel');
                  };
                  // Add upload methods to the scope:
                  angular.extend($scope, uploadMethods);
                  // The fileupload widget will initialize with
                  // the options provided via "data-"-parameters,
                  // as well as those given via options object:
                  $element.fileupload(angular.extend(
                      {scope: $scope},
                      fileUpload.defaults
                  )).on('fileuploadadd', function (e, data) {
                      data.scope = $scope;
                  }).on('fileuploadfail', function (e, data) {
                      if (data.errorThrown === 'abort') {
                          return;
                      }
                      if (data.dataType &&
                          data.dataType.indexOf('json') === data.dataType.length - 4) {
                          try {
                              data.result = angular.fromJson(data.jqXHR.responseText);
                          } catch (ignore) {
                          }
                      }
                  }).on([
                      'fileuploadadd',
                      'fileuploadsubmit',
                      'fileuploadsend',
                      'fileuploaddone',
                      'fileuploadfail',
                      'fileuploadalways',
                      'fileuploadprogress',
                      'fileuploadprogressall',
                      'fileuploadstart',
                      'fileuploadstop',
                      'fileuploadchange',
                      'fileuploadpaste',
                      'fileuploaddrop',
                      'fileuploaddragover',
                      'fileuploadchunksend',
                      'fileuploadchunkdone',
                      'fileuploadchunkfail',
                      'fileuploadchunkalways',
                      'fileuploadprocessstart',
                      'fileuploadprocess',
                      'fileuploadprocessdone',
                      'fileuploadprocessfail',
                      'fileuploadprocessalways',
                      'fileuploadprocessstop'
                  ].join(' '), function (e, data) {
                      if ($scope.$emit(e.type, data).defaultPrevented) {
                          e.preventDefault();
                      }
                  }).on('remove', function () {
                      // Remove upload methods from the scope,
                      // when the widget is removed:
                      var method;
                      for (method in uploadMethods) {
                          if (uploadMethods.hasOwnProperty(method)) {
                              delete $scope[method];
                          }
                      }
                  });
                  // Observe option changes:
                  $scope.$watch(
                      $attrs.fileUpload,
                      function (newOptions) {
                          if (newOptions) {
                              $element.fileupload('option', newOptions);
                          }
                      }
                  );
              }
          ])
  
          // Provide File Upload progress feedback:
          .controller('FileUploadProgressController', [
              '$scope', '$attrs', '$parse',
              function ($scope, $attrs, $parse) {
                  var fn = $parse($attrs.fileUploadProgress),
                      update = function () {
                          var progress = fn($scope);
                          if (!progress || !progress.total) {
                              return;
                          }
                          $scope.num = Math.floor(
                              progress.loaded / progress.total * 100
                          );
                      };
                  update();
                  $scope.$watch(
                      $attrs.fileUploadProgress + '.loaded',
                      function (newValue, oldValue) {
                          if (newValue !== oldValue) {
                              update();
                          }
                      }
                  );
              }
          ])
  
          // Display File Upload previews:
          .controller('FileUploadPreviewController', [
              '$scope', '$element', '$attrs',
              function ($scope, $element, $attrs) {
                  $scope.$watch(
                      $attrs.fileUploadPreview + '.preview',
                      function (preview) {
                          $element.empty();
                          if (preview) {
                              $element.append(preview);
                          }
                      }
                  );
              }
          ])
  
          .directive('fileUpload', function () {
              return {
                  controller: 'FileUploadController',
                  scope: true
              };
          })
  
          .directive('fileUploadProgress', function () {
              return {
                  controller: 'FileUploadProgressController',
                  scope: true
              };
          })
  
          .directive('fileUploadPreview', function () {
              return {
                  controller: 'FileUploadPreviewController'
              };
          })
  
          // Enhance the HTML5 download attribute to
          // allow drag&drop of files to the desktop:
          .directive('download', function () {
              return function (scope, elm) {
                  elm.on('dragstart', function (e) {
                      try {
                          e.originalEvent.dataTransfer.setData(
                              'DownloadURL',
                              [
                                  'application/octet-stream',
                                  elm.prop('download'),
                                  elm.prop('href')
                              ].join(':')
                          );
                      } catch (ignore) {
                      }
                  });
              };
          });
  
  }));
  