File: D:/HostingSpaces/SBogers10/vebon.komma.pro/wwwroot/js/lib.js.map
{"version":3,"sources":["ng-file-upload.js","ngDialog.min.js"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AC30EA;AACA","file":"lib.js","sourcesContent":["/**!\n * AngularJS file upload directives and services. Supoorts: file upload/drop/paste, resume, cancel/abort,\n * progress, resize, thumbnail, preview, validation and CORS\n * @author Danial <danial.farid@gmail.com>\n * @version 12.0.4\n */\n\nif (window.XMLHttpRequest && !(window.FileAPI && FileAPI.shouldLoad)) {\n window.XMLHttpRequest.prototype.setRequestHeader = (function (orig) {\n return function (header, value) {\n if (header === '__setXHR_') {\n var val = value(this);\n // fix for angular < 1.2.0\n if (val instanceof Function) {\n val(this);\n }\n } else {\n orig.apply(this, arguments);\n }\n };\n })(window.XMLHttpRequest.prototype.setRequestHeader);\n}\n\nvar ngFileUpload = angular.module('ngFileUpload', []);\n\nngFileUpload.version = '12.0.4';\n\nngFileUpload.service('UploadBase', ['$http', '$q', '$timeout', function ($http, $q, $timeout) {\n var upload = this;\n upload.promisesCount = 0;\n\n this.isResumeSupported = function () {\n return window.Blob && window.Blob.prototype.slice;\n };\n\n var resumeSupported = this.isResumeSupported();\n\n function sendHttp(config) {\n config.method = config.method || 'POST';\n config.headers = config.headers || {};\n\n var deferred = config._deferred = config._deferred || $q.defer();\n var promise = deferred.promise;\n\n function notifyProgress(e) {\n if (deferred.notify) {\n deferred.notify(e);\n }\n if (promise.progressFunc) {\n $timeout(function () {\n promise.progressFunc(e);\n });\n }\n }\n\n function getNotifyEvent(n) {\n if (config._start != null && resumeSupported) {\n return {\n loaded: n.loaded + config._start,\n total: (config._file && config._file.size) || n.total,\n type: n.type, config: config,\n lengthComputable: true, target: n.target\n };\n } else {\n return n;\n }\n }\n\n if (!config.disableProgress) {\n config.headers.__setXHR_ = function () {\n return function (xhr) {\n if (!xhr || !xhr.upload || !xhr.upload.addEventListener) return;\n config.__XHR = xhr;\n if (config.xhrFn) config.xhrFn(xhr);\n xhr.upload.addEventListener('progress', function (e) {\n e.config = config;\n notifyProgress(getNotifyEvent(e));\n }, false);\n //fix for firefox not firing upload progress end, also IE8-9\n xhr.upload.addEventListener('load', function (e) {\n if (e.lengthComputable) {\n e.config = config;\n notifyProgress(getNotifyEvent(e));\n }\n }, false);\n };\n };\n }\n\n function uploadWithAngular() {\n $http(config).then(function (r) {\n if (resumeSupported && config._chunkSize && !config._finished && config._file) {\n notifyProgress({\n loaded: config._end,\n total: config._file && config._file.size,\n config: config, type: 'progress'\n }\n );\n upload.upload(config, true);\n } else {\n if (config._finished) delete config._finished;\n deferred.resolve(r);\n }\n }, function (e) {\n deferred.reject(e);\n }, function (n) {\n deferred.notify(n);\n }\n );\n }\n\n if (!resumeSupported) {\n uploadWithAngular();\n } else if (config._chunkSize && config._end && !config._finished) {\n config._start = config._end;\n config._end += config._chunkSize;\n uploadWithAngular();\n } else if (config.resumeSizeUrl) {\n $http.get(config.resumeSizeUrl).then(function (resp) {\n if (config.resumeSizeResponseReader) {\n config._start = config.resumeSizeResponseReader(resp.data);\n } else {\n config._start = parseInt((resp.data.size == null ? resp.data : resp.data.size).toString());\n }\n if (config._chunkSize) {\n config._end = config._start + config._chunkSize;\n }\n uploadWithAngular();\n }, function (e) {\n throw e;\n });\n } else if (config.resumeSize) {\n config.resumeSize().then(function (size) {\n config._start = size;\n uploadWithAngular();\n }, function (e) {\n throw e;\n });\n } else {\n if (config._chunkSize) {\n config._start = 0;\n config._end = config._start + config._chunkSize;\n }\n uploadWithAngular();\n }\n\n\n promise.success = function (fn) {\n promise.then(function (response) {\n fn(response.data, response.status, response.headers, config);\n });\n return promise;\n };\n\n promise.error = function (fn) {\n promise.then(null, function (response) {\n fn(response.data, response.status, response.headers, config);\n });\n return promise;\n };\n\n promise.progress = function (fn) {\n promise.progressFunc = fn;\n promise.then(null, null, function (n) {\n fn(n);\n });\n return promise;\n };\n promise.abort = promise.pause = function () {\n if (config.__XHR) {\n $timeout(function () {\n config.__XHR.abort();\n });\n }\n return promise;\n };\n promise.xhr = function (fn) {\n config.xhrFn = (function (origXhrFn) {\n return function () {\n if (origXhrFn) origXhrFn.apply(promise, arguments);\n fn.apply(promise, arguments);\n };\n })(config.xhrFn);\n return promise;\n };\n\n upload.promisesCount++;\n promise['finally'](function () {\n upload.promisesCount--;\n });\n return promise;\n }\n\n this.isUploadInProgress = function () {\n return upload.promisesCount > 0;\n };\n\n this.rename = function (file, name) {\n file.ngfName = name;\n return file;\n };\n\n this.jsonBlob = function (val) {\n if (val != null && !angular.isString(val)) {\n val = JSON.stringify(val);\n }\n var blob = new window.Blob([val], {type: 'application/json'});\n blob._ngfBlob = true;\n return blob;\n };\n\n this.json = function (val) {\n return angular.toJson(val);\n };\n\n function copy(obj) {\n var clone = {};\n for (var key in obj) {\n if (obj.hasOwnProperty(key)) {\n clone[key] = obj[key];\n }\n }\n return clone;\n }\n\n this.isFile = function (file) {\n return file != null && (file instanceof window.Blob || (file.flashId && file.name && file.size));\n };\n\n this.upload = function (config, internal) {\n function toResumeFile(file, formData) {\n if (file._ngfBlob) return file;\n config._file = config._file || file;\n if (config._start != null && resumeSupported) {\n if (config._end && config._end >= file.size) {\n config._finished = true;\n config._end = file.size;\n }\n var slice = file.slice(config._start, config._end || file.size);\n slice.name = file.name;\n slice.ngfName = file.ngfName;\n if (config._chunkSize) {\n formData.append('_chunkSize', config._chunkSize);\n formData.append('_currentChunkSize', config._end - config._start);\n formData.append('_chunkNumber', Math.floor(config._start / config._chunkSize));\n formData.append('_totalSize', config._file.size);\n }\n return slice;\n }\n return file;\n }\n\n function addFieldToFormData(formData, val, key) {\n if (val !== undefined) {\n if (angular.isDate(val)) {\n val = val.toISOString();\n }\n if (angular.isString(val)) {\n formData.append(key, val);\n } else if (upload.isFile(val)) {\n var file = toResumeFile(val, formData);\n var split = key.split(',');\n if (split[1]) {\n file.ngfName = split[1].replace(/^\\s+|\\s+$/g, '');\n key = split[0];\n }\n config._fileKey = config._fileKey || key;\n formData.append(key, file, file.ngfName || file.name);\n } else {\n if (angular.isObject(val)) {\n if (val.$$ngfCircularDetection) throw 'ngFileUpload: Circular reference in config.data. Make sure specified data for Upload.upload() has no circular reference: ' + key;\n\n val.$$ngfCircularDetection = true;\n try {\n for (var k in val) {\n if (val.hasOwnProperty(k) && k !== '$$ngfCircularDetection') {\n var objectKey = config.objectKey == null ? '[i]' : config.objectKey;\n if (val.length && parseInt(k) > -1) {\n objectKey = config.arrayKey == null ? objectKey : config.arrayKey;\n }\n addFieldToFormData(formData, val[k], key + objectKey.replace(/[ik]/g, k));\n }\n }\n } finally {\n delete val.$$ngfCircularDetection;\n }\n } else {\n formData.append(key, val);\n }\n }\n }\n }\n\n function digestConfig() {\n config._chunkSize = upload.translateScalars(config.resumeChunkSize);\n config._chunkSize = config._chunkSize ? parseInt(config._chunkSize.toString()) : null;\n\n config.headers = config.headers || {};\n config.headers['Content-Type'] = undefined;\n config.transformRequest = config.transformRequest ?\n (angular.isArray(config.transformRequest) ?\n config.transformRequest : [config.transformRequest]) : [];\n config.transformRequest.push(function (data) {\n var formData = new window.FormData(), key;\n data = data || config.fields || {};\n if (config.file) {\n data.file = config.file;\n }\n for (key in data) {\n if (data.hasOwnProperty(key)) {\n var val = data[key];\n if (config.formDataAppender) {\n config.formDataAppender(formData, key, val);\n } else {\n addFieldToFormData(formData, val, key);\n }\n }\n }\n\n return formData;\n });\n }\n\n if (!internal) config = copy(config);\n if (!config._isDigested) {\n config._isDigested = true;\n digestConfig();\n }\n\n return sendHttp(config);\n };\n\n this.http = function (config) {\n config = copy(config);\n config.transformRequest = config.transformRequest || function (data) {\n if ((window.ArrayBuffer && data instanceof window.ArrayBuffer) || data instanceof window.Blob) {\n return data;\n }\n return $http.defaults.transformRequest[0].apply(this, arguments);\n };\n config._chunkSize = upload.translateScalars(config.resumeChunkSize);\n config._chunkSize = config._chunkSize ? parseInt(config._chunkSize.toString()) : null;\n\n return sendHttp(config);\n };\n\n this.translateScalars = function (str) {\n if (angular.isString(str)) {\n if (str.search(/kb/i) === str.length - 2) {\n return parseFloat(str.substring(0, str.length - 2) * 1024);\n } else if (str.search(/mb/i) === str.length - 2) {\n return parseFloat(str.substring(0, str.length - 2) * 1048576);\n } else if (str.search(/gb/i) === str.length - 2) {\n return parseFloat(str.substring(0, str.length - 2) * 1073741824);\n } else if (str.search(/b/i) === str.length - 1) {\n return parseFloat(str.substring(0, str.length - 1));\n } else if (str.search(/s/i) === str.length - 1) {\n return parseFloat(str.substring(0, str.length - 1));\n } else if (str.search(/m/i) === str.length - 1) {\n return parseFloat(str.substring(0, str.length - 1) * 60);\n } else if (str.search(/h/i) === str.length - 1) {\n return parseFloat(str.substring(0, str.length - 1) * 3600);\n }\n }\n return str;\n };\n\n this.urlToBlob = function(url) {\n var defer = $q.defer();\n $http({url: url, method: 'get', responseType: 'arraybuffer'}).then(function (resp) {\n var arrayBufferView = new Uint8Array(resp.data);\n var type = resp.headers('content-type') || 'image/WebP';\n var blob = new window.Blob([arrayBufferView], {type: type});\n defer.resolve(blob);\n //var split = type.split('[/;]');\n //blob.name = url.substring(0, 150).replace(/\\W+/g, '') + '.' + (split.length > 1 ? split[1] : 'jpg');\n }, function (e) {\n defer.reject(e);\n });\n return defer.promise;\n };\n\n this.setDefaults = function (defaults) {\n this.defaults = defaults || {};\n };\n\n this.defaults = {};\n this.version = ngFileUpload.version;\n}\n\n]);\n\nngFileUpload.service('Upload', ['$parse', '$timeout', '$compile', '$q', 'UploadExif', function ($parse, $timeout, $compile, $q, UploadExif) {\n var upload = UploadExif;\n upload.getAttrWithDefaults = function (attr, name) {\n if (attr[name] != null) return attr[name];\n var def = upload.defaults[name];\n return (def == null ? def : (angular.isString(def) ? def : JSON.stringify(def)));\n };\n\n upload.attrGetter = function (name, attr, scope, params) {\n var attrVal = this.getAttrWithDefaults(attr, name);\n if (scope) {\n try {\n if (params) {\n return $parse(attrVal)(scope, params);\n } else {\n return $parse(attrVal)(scope);\n }\n } catch (e) {\n // hangle string value without single qoute\n if (name.search(/min|max|pattern/i)) {\n return attrVal;\n } else {\n throw e;\n }\n }\n } else {\n return attrVal;\n }\n };\n\n upload.shouldUpdateOn = function (type, attr, scope) {\n var modelOptions = upload.attrGetter('ngModelOptions', attr, scope);\n if (modelOptions && modelOptions.updateOn) {\n return modelOptions.updateOn.split(' ').indexOf(type) > -1;\n }\n return true;\n };\n\n upload.emptyPromise = function () {\n var d = $q.defer();\n var args = arguments;\n $timeout(function () {\n d.resolve.apply(d, args);\n });\n return d.promise;\n };\n\n upload.rejectPromise = function () {\n var d = $q.defer();\n var args = arguments;\n $timeout(function () {\n d.reject.apply(d, args);\n });\n return d.promise;\n };\n\n upload.happyPromise = function (promise, data) {\n var d = $q.defer();\n promise.then(function (result) {\n d.resolve(result);\n }, function (error) {\n $timeout(function () {\n throw error;\n });\n d.resolve(data);\n });\n return d.promise;\n };\n\n function applyExifRotations(files, attr, scope) {\n var promises = [upload.emptyPromise()];\n angular.forEach(files, function (f, i) {\n if (f.type.indexOf('image/jpeg') === 0 && upload.attrGetter('ngfFixOrientation', attr, scope, {$file: f})) {\n promises.push(upload.happyPromise(upload.applyExifRotation(f), f).then(function (fixedFile) {\n files.splice(i, 1, fixedFile);\n }));\n }\n });\n return $q.all(promises);\n }\n\n function resize(files, attr, scope) {\n var resizeVal = upload.attrGetter('ngfResize', attr, scope);\n if (!resizeVal || !upload.isResizeSupported() || !files.length) return upload.emptyPromise();\n if (resizeVal instanceof Function) {\n var defer = $q.defer();\n resizeVal(files).then(function (p) {\n resizeWithParams(p, files, attr, scope).then(function (r) {\n defer.resolve(r);\n }, function (e) {\n defer.reject(e);\n });\n }, function (e) {\n defer.reject(e);\n });\n } else {\n return resizeWithParams(resizeVal, files, attr, scope);\n }\n }\n\n function resizeWithParams(param, files, attr, scope) {\n var promises = [upload.emptyPromise()];\n\n function handleFile(f, i) {\n if (f.type.indexOf('image') === 0) {\n if (param.pattern && !upload.validatePattern(f, param.pattern)) return;\n var promise = upload.resize(f, param.width, param.height, param.quality,\n param.type, param.ratio, param.centerCrop, function (width, height) {\n return upload.attrGetter('ngfResizeIf', attr, scope,\n {$width: width, $height: height, $file: f});\n }, param.restoreExif !== false);\n promises.push(promise);\n promise.then(function (resizedFile) {\n files.splice(i, 1, resizedFile);\n }, function (e) {\n f.$error = 'resize';\n f.$errorParam = (e ? (e.message ? e.message : e) + ': ' : '') + (f && f.name);\n });\n }\n }\n\n for (var i = 0; i < files.length; i++) {\n handleFile(files[i], i);\n }\n return $q.all(promises);\n }\n\n upload.updateModel = function (ngModel, attr, scope, fileChange, files, evt, noDelay) {\n function update(files, invalidFiles, newFiles, dupFiles, isSingleModel) {\n attr.$$ngfPrevValidFiles = files;\n attr.$$ngfPrevInvalidFiles = invalidFiles;\n var file = files && files.length ? files[0] : null;\n var invalidFile = invalidFiles && invalidFiles.length ? invalidFiles[0] : null;\n\n if (ngModel) {\n upload.applyModelValidation(ngModel, files);\n ngModel.$setViewValue(isSingleModel ? file : files);\n }\n\n if (fileChange) {\n $parse(fileChange)(scope, {\n $files: files,\n $file: file,\n $newFiles: newFiles,\n $duplicateFiles: dupFiles,\n $invalidFiles: invalidFiles,\n $invalidFile: invalidFile,\n $event: evt\n });\n }\n\n var invalidModel = upload.attrGetter('ngfModelInvalid', attr);\n if (invalidModel) {\n $timeout(function () {\n $parse(invalidModel).assign(scope, isSingleModel ? invalidFile : invalidFiles);\n });\n }\n $timeout(function () {\n // scope apply changes\n });\n }\n\n var allNewFiles, dupFiles = [], prevValidFiles, prevInvalidFiles,\n invalids = [], valids = [];\n\n function removeDuplicates() {\n function equals(f1, f2) {\n return f1.name === f2.name && (f1.$ngfOrigSize || f1.size) === (f2.$ngfOrigSize || f2.size) &&\n f1.type === f2.type;\n }\n\n function isInPrevFiles(f) {\n var j;\n for (j = 0; j < prevValidFiles.length; j++) {\n if (equals(f, prevValidFiles[j])) {\n return true;\n }\n }\n for (j = 0; j < prevInvalidFiles.length; j++) {\n if (equals(f, prevInvalidFiles[j])) {\n return true;\n }\n }\n return false;\n }\n\n if (files) {\n allNewFiles = [];\n dupFiles = [];\n for (var i = 0; i < files.length; i++) {\n if (isInPrevFiles(files[i])) {\n dupFiles.push(files[i]);\n } else {\n allNewFiles.push(files[i]);\n }\n }\n }\n }\n\n function toArray(v) {\n return angular.isArray(v) ? v : [v];\n }\n\n function separateInvalids() {\n valids = [];\n invalids = [];\n angular.forEach(allNewFiles, function (file) {\n if (file.$error) {\n invalids.push(file);\n } else {\n valids.push(file);\n }\n });\n }\n\n function resizeAndUpdate() {\n function updateModel() {\n $timeout(function () {\n update(keep ? prevValidFiles.concat(valids) : valids,\n keep ? prevInvalidFiles.concat(invalids) : invalids,\n files, dupFiles, isSingleModel);\n }, options && options.debounce ? options.debounce.change || options.debounce : 0);\n }\n\n resize(validateAfterResize ? allNewFiles : valids, attr, scope).then(function () {\n if (validateAfterResize) {\n upload.validate(allNewFiles, prevValidFiles.length, ngModel, attr, scope).then(function () {\n separateInvalids();\n updateModel();\n });\n } else {\n updateModel();\n }\n }, function (e) {\n throw 'Could not resize files ' + e;\n });\n }\n\n prevValidFiles = attr.$$ngfPrevValidFiles || [];\n prevInvalidFiles = attr.$$ngfPrevInvalidFiles || [];\n if (ngModel && ngModel.$modelValue) {\n prevValidFiles = toArray(ngModel.$modelValue);\n }\n\n var keep = upload.attrGetter('ngfKeep', attr, scope);\n allNewFiles = (files || []).slice(0);\n if (keep === 'distinct' || upload.attrGetter('ngfKeepDistinct', attr, scope) === true) {\n removeDuplicates(attr, scope);\n }\n\n var isSingleModel = !keep && !upload.attrGetter('ngfMultiple', attr, scope) && !upload.attrGetter('multiple', attr);\n\n if (keep && !allNewFiles.length) return;\n\n upload.attrGetter('ngfBeforeModelChange', attr, scope, {\n $files: files,\n $file: files && files.length ? files[0] : null,\n $newFiles: allNewFiles,\n $duplicateFiles: dupFiles,\n $event: evt\n });\n\n var validateAfterResize = upload.attrGetter('ngfValidateAfterResize', attr, scope);\n\n var options = upload.attrGetter('ngModelOptions', attr, scope);\n upload.validate(allNewFiles, prevValidFiles.length, ngModel, attr, scope).then(function () {\n if (noDelay) {\n update(allNewFiles, [], files, dupFiles, isSingleModel);\n } else {\n if ((!options || !options.allowInvalid) && !validateAfterResize) {\n separateInvalids();\n } else {\n valids = allNewFiles;\n }\n if (upload.attrGetter('ngfFixOrientation', attr, scope) && upload.isExifSupported()) {\n applyExifRotations(valids, attr, scope).then(function () {\n resizeAndUpdate();\n });\n } else {\n resizeAndUpdate();\n }\n }\n });\n };\n\n return upload;\n}]);\n\nngFileUpload.directive('ngfSelect', ['$parse', '$timeout', '$compile', 'Upload', function ($parse, $timeout, $compile, Upload) {\n var generatedElems = [];\n\n function isDelayedClickSupported(ua) {\n // fix for android native browser < 4.4 and safari windows\n var m = ua.match(/Android[^\\d]*(\\d+)\\.(\\d+)/);\n if (m && m.length > 2) {\n var v = Upload.defaults.androidFixMinorVersion || 4;\n return parseInt(m[1]) < 4 || (parseInt(m[1]) === v && parseInt(m[2]) < v);\n }\n\n // safari on windows\n return ua.indexOf('Chrome') === -1 && /.*Windows.*Safari.*/.test(ua);\n }\n\n function linkFileSelect(scope, elem, attr, ngModel, $parse, $timeout, $compile, upload) {\n /** @namespace attr.ngfSelect */\n /** @namespace attr.ngfChange */\n /** @namespace attr.ngModel */\n /** @namespace attr.ngModelOptions */\n /** @namespace attr.ngfMultiple */\n /** @namespace attr.ngfCapture */\n /** @namespace attr.ngfValidate */\n /** @namespace attr.ngfKeep */\n var attrGetter = function (name, scope) {\n return upload.attrGetter(name, attr, scope);\n };\n\n function isInputTypeFile() {\n return elem[0].tagName.toLowerCase() === 'input' && attr.type && attr.type.toLowerCase() === 'file';\n }\n\n function fileChangeAttr() {\n return attrGetter('ngfChange') || attrGetter('ngfSelect');\n }\n\n function changeFn(evt) {\n if (upload.shouldUpdateOn('change', attr, scope)) {\n var fileList = evt.__files_ || (evt.target && evt.target.files), files = [];\n for (var i = 0; i < fileList.length; i++) {\n files.push(fileList[i]);\n }\n upload.updateModel(ngModel, attr, scope, fileChangeAttr(),\n files.length ? files : null, evt);\n }\n }\n\n upload.registerModelChangeValidator(ngModel, attr, scope);\n\n var unwatches = [];\n unwatches.push(scope.$watch(attrGetter('ngfMultiple'), function () {\n fileElem.attr('multiple', attrGetter('ngfMultiple', scope));\n }));\n unwatches.push(scope.$watch(attrGetter('ngfCapture'), function () {\n fileElem.attr('capture', attrGetter('ngfCapture', scope));\n }));\n unwatches.push(scope.$watch(attrGetter('ngfAccept'), function () {\n fileElem.attr('accept', attrGetter('ngfAccept', scope));\n }));\n attr.$observe('accept', function () {\n fileElem.attr('accept', attrGetter('accept'));\n });\n unwatches.push(function () {\n if (attr.$$observers) delete attr.$$observers.accept;\n });\n function bindAttrToFileInput(fileElem) {\n if (elem !== fileElem) {\n for (var i = 0; i < elem[0].attributes.length; i++) {\n var attribute = elem[0].attributes[i];\n if (attribute.name !== 'type' && attribute.name !== 'class' && attribute.name !== 'style') {\n if (attribute.value == null || attribute.value === '') {\n if (attribute.name === 'required') attribute.value = 'required';\n if (attribute.name === 'multiple') attribute.value = 'multiple';\n }\n fileElem.attr(attribute.name, attribute.name === 'id' ? 'ngf-' + attribute.value : attribute.value);\n }\n }\n }\n }\n\n function createFileInput() {\n if (isInputTypeFile()) {\n return elem;\n }\n\n var fileElem = angular.element('<input type=\"file\">');\n\n bindAttrToFileInput(fileElem);\n\n var label = angular.element('<label>upload</label>');\n label.css('visibility', 'hidden').css('position', 'absolute').css('overflow', 'hidden')\n .css('width', '0px').css('height', '0px').css('border', 'none')\n .css('margin', '0px').css('padding', '0px').attr('tabindex', '-1');\n generatedElems.push({el: elem, ref: label});\n\n document.body.appendChild(label.append(fileElem)[0]);\n\n return fileElem;\n }\n\n var initialTouchStartY = 0;\n\n function clickHandler(evt) {\n if (elem.attr('disabled')) return false;\n if (attrGetter('ngfSelectDisabled', scope)) return;\n\n var r = handleTouch(evt);\n if (r != null) return r;\n\n resetModel(evt);\n\n // fix for md when the element is removed from the DOM and added back #460\n try {\n if (!isInputTypeFile() && !document.body.contains(fileElem[0])) {\n generatedElems.push({el: elem, ref: fileElem.parent()});\n document.body.appendChild(fileElem.parent()[0]);\n fileElem.bind('change', changeFn);\n }\n } catch(e){/*ignore*/}\n\n if (isDelayedClickSupported(navigator.userAgent)) {\n setTimeout(function () {\n fileElem[0].click();\n }, 0);\n } else {\n fileElem[0].click();\n }\n\n return false;\n }\n\n function handleTouch(evt) {\n var touches = evt.changedTouches || (evt.originalEvent && evt.originalEvent.changedTouches);\n if (evt.type === 'touchstart') {\n initialTouchStartY = touches ? touches[0].clientY : 0;\n return true; // don't block event default\n } else {\n evt.stopPropagation();\n evt.preventDefault();\n\n // prevent scroll from triggering event\n if (evt.type === 'touchend') {\n var currentLocation = touches ? touches[0].clientY : 0;\n if (Math.abs(currentLocation - initialTouchStartY) > 20) return false;\n }\n }\n }\n\n var fileElem = elem;\n\n function resetModel(evt) {\n if (upload.shouldUpdateOn('click', attr, scope) && fileElem.val()) {\n fileElem.val(null);\n upload.updateModel(ngModel, attr, scope, fileChangeAttr(), null, evt, true);\n }\n }\n\n if (!isInputTypeFile()) {\n fileElem = createFileInput();\n }\n fileElem.bind('change', changeFn);\n\n if (!isInputTypeFile()) {\n elem.bind('click touchstart touchend', clickHandler);\n } else {\n elem.bind('click', resetModel);\n }\n\n function ie10SameFileSelectFix(evt) {\n if (fileElem && !fileElem.attr('__ngf_ie10_Fix_')) {\n if (!fileElem[0].parentNode) {\n fileElem = null;\n return;\n }\n evt.preventDefault();\n evt.stopPropagation();\n fileElem.unbind('click');\n var clone = fileElem.clone();\n fileElem.replaceWith(clone);\n fileElem = clone;\n fileElem.attr('__ngf_ie10_Fix_', 'true');\n fileElem.bind('change', changeFn);\n fileElem.bind('click', ie10SameFileSelectFix);\n fileElem[0].click();\n return false;\n } else {\n fileElem.removeAttr('__ngf_ie10_Fix_');\n }\n }\n\n if (navigator.appVersion.indexOf('MSIE 10') !== -1) {\n fileElem.bind('click', ie10SameFileSelectFix);\n }\n\n if (ngModel) ngModel.$formatters.push(function (val) {\n if (val == null || val.length === 0) {\n if (fileElem.val()) {\n fileElem.val(null);\n }\n }\n return val;\n });\n\n scope.$on('$destroy', function () {\n if (!isInputTypeFile()) fileElem.parent().remove();\n angular.forEach(unwatches, function (unwatch) {\n unwatch();\n });\n });\n\n $timeout(function () {\n for (var i = 0; i < generatedElems.length; i++) {\n var g = generatedElems[i];\n if (!document.body.contains(g.el[0])) {\n generatedElems.splice(i, 1);\n g.ref.remove();\n }\n }\n });\n\n if (window.FileAPI && window.FileAPI.ngfFixIE) {\n window.FileAPI.ngfFixIE(elem, fileElem, changeFn);\n }\n }\n\n return {\n restrict: 'AEC',\n require: '?ngModel',\n link: function (scope, elem, attr, ngModel) {\n linkFileSelect(scope, elem, attr, ngModel, $parse, $timeout, $compile, Upload);\n }\n };\n}]);\n\n(function () {\n\n ngFileUpload.service('UploadDataUrl', ['UploadBase', '$timeout', '$q', function (UploadBase, $timeout, $q) {\n var upload = UploadBase;\n upload.base64DataUrl = function (file) {\n if (angular.isArray(file)) {\n var d = $q.defer(), count = 0;\n angular.forEach(file, function (f) {\n upload.dataUrl(f, true)['finally'](function () {\n count++;\n if (count === file.length) {\n var urls = [];\n angular.forEach(file, function (ff) {\n urls.push(ff.$ngfDataUrl);\n });\n d.resolve(urls, file);\n }\n });\n });\n return d.promise;\n } else {\n return upload.dataUrl(file, true);\n }\n };\n upload.dataUrl = function (file, disallowObjectUrl) {\n if (!file) return upload.emptyPromise(file, file);\n if ((disallowObjectUrl && file.$ngfDataUrl != null) || (!disallowObjectUrl && file.$ngfBlobUrl != null)) {\n return upload.emptyPromise(disallowObjectUrl ? file.$ngfDataUrl : file.$ngfBlobUrl, file);\n }\n var p = disallowObjectUrl ? file.$$ngfDataUrlPromise : file.$$ngfBlobUrlPromise;\n if (p) return p;\n\n var deferred = $q.defer();\n $timeout(function () {\n if (window.FileReader && file &&\n (!window.FileAPI || navigator.userAgent.indexOf('MSIE 8') === -1 || file.size < 20000) &&\n (!window.FileAPI || navigator.userAgent.indexOf('MSIE 9') === -1 || file.size < 4000000)) {\n //prefer URL.createObjectURL for handling refrences to files of all sizes\n //since it doesn´t build a large string in memory\n var URL = window.URL || window.webkitURL;\n if (URL && URL.createObjectURL && !disallowObjectUrl) {\n var url;\n try {\n url = URL.createObjectURL(file);\n } catch (e) {\n $timeout(function () {\n file.$ngfBlobUrl = '';\n deferred.reject();\n });\n return;\n }\n $timeout(function () {\n file.$ngfBlobUrl = url;\n if (url) {\n deferred.resolve(url, file);\n upload.blobUrls = upload.blobUrls || [];\n upload.blobUrlsTotalSize = upload.blobUrlsTotalSize || 0;\n upload.blobUrls.push({url: url, size: file.size});\n upload.blobUrlsTotalSize += file.size || 0;\n var maxMemory = upload.defaults.blobUrlsMaxMemory || 268435456;\n var maxLength = upload.defaults.blobUrlsMaxQueueSize || 200;\n while ((upload.blobUrlsTotalSize > maxMemory || upload.blobUrls.length > maxLength) && upload.blobUrls.length > 1) {\n var obj = upload.blobUrls.splice(0, 1)[0];\n URL.revokeObjectURL(obj.url);\n upload.blobUrlsTotalSize -= obj.size;\n }\n }\n });\n } else {\n var fileReader = new FileReader();\n fileReader.onload = function (e) {\n $timeout(function () {\n file.$ngfDataUrl = e.target.result;\n deferred.resolve(e.target.result, file);\n $timeout(function () {\n delete file.$ngfDataUrl;\n }, 1000);\n });\n };\n fileReader.onerror = function () {\n $timeout(function () {\n file.$ngfDataUrl = '';\n deferred.reject();\n });\n };\n fileReader.readAsDataURL(file);\n }\n } else {\n $timeout(function () {\n file[disallowObjectUrl ? '$ngfDataUrl' : '$ngfBlobUrl'] = '';\n deferred.reject();\n });\n }\n });\n\n if (disallowObjectUrl) {\n p = file.$$ngfDataUrlPromise = deferred.promise;\n } else {\n p = file.$$ngfBlobUrlPromise = deferred.promise;\n }\n p['finally'](function () {\n delete file[disallowObjectUrl ? '$$ngfDataUrlPromise' : '$$ngfBlobUrlPromise'];\n });\n return p;\n };\n return upload;\n }]);\n\n function getTagType(el) {\n if (el.tagName.toLowerCase() === 'img') return 'image';\n if (el.tagName.toLowerCase() === 'audio') return 'audio';\n if (el.tagName.toLowerCase() === 'video') return 'video';\n return /./;\n }\n\n function linkFileDirective(Upload, $timeout, scope, elem, attr, directiveName, resizeParams, isBackground) {\n function constructDataUrl(file) {\n var disallowObjectUrl = Upload.attrGetter('ngfNoObjectUrl', attr, scope);\n Upload.dataUrl(file, disallowObjectUrl)['finally'](function () {\n $timeout(function () {\n var src = (disallowObjectUrl ? file.$ngfDataUrl : file.$ngfBlobUrl) || file.$ngfDataUrl;\n if (isBackground) {\n elem.css('background-image', 'url(\\'' + (src || '') + '\\')');\n } else {\n elem.attr('src', src);\n }\n if (src) {\n elem.removeClass('ng-hide');\n } else {\n elem.addClass('ng-hide');\n }\n });\n });\n }\n\n $timeout(function () {\n var unwatch = scope.$watch(attr[directiveName], function (file) {\n var size = resizeParams;\n if (directiveName === 'ngfThumbnail') {\n if (!size) {\n size = {width: elem[0].clientWidth, height: elem[0].clientHeight};\n }\n if (size.width === 0 && window.getComputedStyle) {\n var style = getComputedStyle(elem[0]);\n size = {\n width: parseInt(style.width.slice(0, -2)),\n height: parseInt(style.height.slice(0, -2))\n };\n }\n }\n\n if (angular.isString(file)) {\n elem.removeClass('ng-hide');\n if (isBackground) {\n return elem.css('background-image', 'url(\\'' + file + '\\')');\n } else {\n return elem.attr('src', file);\n }\n }\n if (file && file.type && file.type.search(getTagType(elem[0])) === 0 &&\n (!isBackground || file.type.indexOf('image') === 0)) {\n if (size && Upload.isResizeSupported()) {\n Upload.resize(file, size.width, size.height, size.quality).then(\n function (f) {\n constructDataUrl(f);\n }, function (e) {\n throw e;\n }\n );\n } else {\n constructDataUrl(file);\n }\n } else {\n elem.addClass('ng-hide');\n }\n });\n\n scope.$on('$destroy', function () {\n unwatch();\n });\n });\n }\n\n\n /** @namespace attr.ngfSrc */\n /** @namespace attr.ngfNoObjectUrl */\n ngFileUpload.directive('ngfSrc', ['Upload', '$timeout', function (Upload, $timeout) {\n return {\n restrict: 'AE',\n link: function (scope, elem, attr) {\n linkFileDirective(Upload, $timeout, scope, elem, attr, 'ngfSrc',\n Upload.attrGetter('ngfResize', attr, scope), false);\n }\n };\n }]);\n\n /** @namespace attr.ngfBackground */\n /** @namespace attr.ngfNoObjectUrl */\n ngFileUpload.directive('ngfBackground', ['Upload', '$timeout', function (Upload, $timeout) {\n return {\n restrict: 'AE',\n link: function (scope, elem, attr) {\n linkFileDirective(Upload, $timeout, scope, elem, attr, 'ngfBackground',\n Upload.attrGetter('ngfResize', attr, scope), true);\n }\n };\n }]);\n\n /** @namespace attr.ngfThumbnail */\n /** @namespace attr.ngfAsBackground */\n /** @namespace attr.ngfSize */\n /** @namespace attr.ngfNoObjectUrl */\n ngFileUpload.directive('ngfThumbnail', ['Upload', '$timeout', function (Upload, $timeout) {\n return {\n restrict: 'AE',\n link: function (scope, elem, attr) {\n var size = Upload.attrGetter('ngfSize', attr, scope);\n linkFileDirective(Upload, $timeout, scope, elem, attr, 'ngfThumbnail', size,\n Upload.attrGetter('ngfAsBackground', attr, scope));\n }\n };\n }]);\n\n ngFileUpload.config(['$compileProvider', function ($compileProvider) {\n if ($compileProvider.imgSrcSanitizationWhitelist) $compileProvider.imgSrcSanitizationWhitelist(/^\\s*(https?|ftp|mailto|tel|local|file|data|blob):/);\n if ($compileProvider.aHrefSanitizationWhitelist) $compileProvider.aHrefSanitizationWhitelist(/^\\s*(https?|ftp|mailto|tel|local|file|data|blob):/);\n }]);\n\n ngFileUpload.filter('ngfDataUrl', ['UploadDataUrl', '$sce', function (UploadDataUrl, $sce) {\n return function (file, disallowObjectUrl, trustedUrl) {\n if (angular.isString(file)) {\n return $sce.trustAsResourceUrl(file);\n }\n var src = file && ((disallowObjectUrl ? file.$ngfDataUrl : file.$ngfBlobUrl) || file.$ngfDataUrl);\n if (file && !src) {\n if (!file.$ngfDataUrlFilterInProgress && angular.isObject(file)) {\n file.$ngfDataUrlFilterInProgress = true;\n UploadDataUrl.dataUrl(file, disallowObjectUrl);\n }\n return '';\n }\n if (file) delete file.$ngfDataUrlFilterInProgress;\n return (file && src ? (trustedUrl ? $sce.trustAsResourceUrl(src) : src) : file) || '';\n };\n }]);\n\n})();\n\nngFileUpload.service('UploadValidate', ['UploadDataUrl', '$q', '$timeout', function (UploadDataUrl, $q, $timeout) {\n var upload = UploadDataUrl;\n\n function globStringToRegex(str) {\n var regexp = '', excludes = [];\n if (str.length > 2 && str[0] === '/' && str[str.length - 1] === '/') {\n regexp = str.substring(1, str.length - 1);\n } else {\n var split = str.split(',');\n if (split.length > 1) {\n for (var i = 0; i < split.length; i++) {\n var r = globStringToRegex(split[i]);\n if (r.regexp) {\n regexp += '(' + r.regexp + ')';\n if (i < split.length - 1) {\n regexp += '|';\n }\n } else {\n excludes = excludes.concat(r.excludes);\n }\n }\n } else {\n if (str.indexOf('!') === 0) {\n excludes.push('^((?!' + globStringToRegex(str.substring(1)).regexp + ').)*$');\n } else {\n if (str.indexOf('.') === 0) {\n str = '*' + str;\n }\n regexp = '^' + str.replace(new RegExp('[.\\\\\\\\+*?\\\\[\\\\^\\\\]$(){}=!<>|:\\\\-]', 'g'), '\\\\$&') + '$';\n regexp = regexp.replace(/\\\\\\*/g, '.*').replace(/\\\\\\?/g, '.');\n }\n }\n }\n return {regexp: regexp, excludes: excludes};\n }\n\n upload.validatePattern = function (file, val) {\n if (!val) {\n return true;\n }\n var pattern = globStringToRegex(val), valid = true;\n if (pattern.regexp && pattern.regexp.length) {\n var regexp = new RegExp(pattern.regexp, 'i');\n valid = (file.type != null && regexp.test(file.type)) ||\n (file.name != null && regexp.test(file.name));\n }\n var len = pattern.excludes.length;\n while (len--) {\n var exclude = new RegExp(pattern.excludes[len], 'i');\n valid = valid && (file.type == null || exclude.test(file.type)) &&\n (file.name == null || exclude.test(file.name));\n }\n return valid;\n };\n\n upload.ratioToFloat = function (val) {\n var r = val.toString(), xIndex = r.search(/[x:]/i);\n if (xIndex > -1) {\n r = parseFloat(r.substring(0, xIndex)) / parseFloat(r.substring(xIndex + 1));\n } else {\n r = parseFloat(r);\n }\n return r;\n };\n\n upload.registerModelChangeValidator = function (ngModel, attr, scope) {\n if (ngModel) {\n ngModel.$formatters.push(function (files) {\n if (ngModel.$dirty) {\n if (files && !angular.isArray(files)) {\n files = [files];\n }\n upload.validate(files, 0, ngModel, attr, scope).then(function () {\n upload.applyModelValidation(ngModel, files);\n });\n }\n });\n }\n };\n\n function markModelAsDirty(ngModel, files) {\n if (files != null && !ngModel.$dirty) {\n if (ngModel.$setDirty) {\n ngModel.$setDirty();\n } else {\n ngModel.$dirty = true;\n }\n }\n }\n\n upload.applyModelValidation = function (ngModel, files) {\n markModelAsDirty(ngModel, files);\n angular.forEach(ngModel.$ngfValidations, function (validation) {\n ngModel.$setValidity(validation.name, validation.valid);\n });\n };\n\n upload.getValidationAttr = function (attr, scope, name, validationName, file) {\n var dName = 'ngf' + name[0].toUpperCase() + name.substr(1);\n var val = upload.attrGetter(dName, attr, scope, {$file: file});\n if (val == null) {\n val = upload.attrGetter('ngfValidate', attr, scope, {$file: file});\n if (val) {\n var split = (validationName || name).split('.');\n val = val[split[0]];\n if (split.length > 1) {\n val = val && val[split[1]];\n }\n }\n }\n return val;\n };\n\n upload.validate = function (files, prevLength, ngModel, attr, scope) {\n ngModel = ngModel || {};\n ngModel.$ngfValidations = ngModel.$ngfValidations || [];\n\n angular.forEach(ngModel.$ngfValidations, function (v) {\n v.valid = true;\n });\n\n var attrGetter = function (name, params) {\n return upload.attrGetter(name, attr, scope, params);\n };\n\n if (files == null || files.length === 0) {\n return upload.emptyPromise(ngModel);\n }\n\n files = files.length === undefined ? [files] : files.slice(0);\n\n function validateSync(name, validationName, fn) {\n if (files) {\n var i = files.length, valid = null;\n while (i--) {\n var file = files[i];\n if (file) {\n var val = upload.getValidationAttr(attr, scope, name, validationName, file);\n if (val != null) {\n if (!fn(file, val, i)) {\n file.$error = name;\n (file.$errorMessages = (file.$errorMessages || {}))[name] = true;\n file.$errorParam = val;\n files.splice(i, 1);\n valid = false;\n }\n }\n }\n }\n if (valid !== null) {\n ngModel.$ngfValidations.push({name: name, valid: valid});\n }\n }\n }\n\n validateSync('maxFiles', null, function (file, val, i) {\n return prevLength + i < val;\n });\n validateSync('pattern', null, upload.validatePattern);\n validateSync('minSize', 'size.min', function (file, val) {\n return file.size + 0.1 >= upload.translateScalars(val);\n });\n validateSync('maxSize', 'size.max', function (file, val) {\n return file.size - 0.1 <= upload.translateScalars(val);\n });\n var totalSize = 0;\n validateSync('maxTotalSize', null, function (file, val) {\n totalSize += file.size;\n if (totalSize > upload.translateScalars(val)) {\n files.splice(0, files.length);\n return false;\n }\n return true;\n });\n\n validateSync('validateFn', null, function (file, r) {\n return r === true || r === null || r === '';\n });\n\n if (!files.length) {\n return upload.emptyPromise(ngModel, ngModel.$ngfValidations);\n }\n\n function validateAsync(name, validationName, type, asyncFn, fn) {\n function resolveResult(defer, file, val) {\n if (val != null) {\n asyncFn(file, val).then(function (d) {\n if (!fn(d, val)) {\n file.$error = name;\n (file.$errorMessages = (file.$errorMessages || {}))[name] = true;\n file.$errorParam = val;\n defer.reject();\n } else {\n defer.resolve();\n }\n }, function () {\n if (attrGetter('ngfValidateForce', {$file: file})) {\n file.$error = name;\n (file.$errorMessages = (file.$errorMessages || {}))[name] = true;\n file.$errorParam = val;\n defer.reject();\n } else {\n defer.resolve();\n }\n });\n } else {\n defer.resolve();\n }\n }\n\n var promises = [upload.emptyPromise()];\n if (files) {\n files = files.length === undefined ? [files] : files;\n angular.forEach(files, function (file) {\n var defer = $q.defer();\n promises.push(defer.promise);\n if (type && (file.type == null || file.type.search(type) !== 0)) {\n defer.resolve();\n return;\n }\n if (name === 'dimensions' && upload.attrGetter('ngfDimensions', attr) != null) {\n upload.imageDimensions(file).then(function (d) {\n resolveResult(defer, file,\n attrGetter('ngfDimensions', {$file: file, $width: d.width, $height: d.height}));\n }, function () {\n defer.reject();\n });\n } else if (name === 'duration' && upload.attrGetter('ngfDuration', attr) != null) {\n upload.mediaDuration(file).then(function (d) {\n resolveResult(defer, file,\n attrGetter('ngfDuration', {$file: file, $duration: d}));\n }, function () {\n defer.reject();\n });\n } else {\n resolveResult(defer, file,\n upload.getValidationAttr(attr, scope, name, validationName, file));\n }\n });\n return $q.all(promises).then(function () {\n ngModel.$ngfValidations.push({name: name, valid: true});\n }, function () {\n ngModel.$ngfValidations.push({name: name, valid: false});\n });\n }\n }\n\n var deffer = $q.defer();\n var promises = [];\n\n promises.push(upload.happyPromise(validateAsync('maxHeight', 'height.max', /image/,\n this.imageDimensions, function (d, val) {\n return d.height <= val;\n })));\n promises.push(upload.happyPromise(validateAsync('minHeight', 'height.min', /image/,\n this.imageDimensions, function (d, val) {\n return d.height >= val;\n })));\n promises.push(upload.happyPromise(validateAsync('maxWidth', 'width.max', /image/,\n this.imageDimensions, function (d, val) {\n return d.width <= val;\n })));\n promises.push(upload.happyPromise(validateAsync('minWidth', 'width.min', /image/,\n this.imageDimensions, function (d, val) {\n return d.width >= val;\n })));\n promises.push(upload.happyPromise(validateAsync('dimensions', null, /image/,\n function (file, val) {\n return upload.emptyPromise(val);\n }, function (r) {\n return r;\n })));\n promises.push(upload.happyPromise(validateAsync('ratio', null, /image/,\n this.imageDimensions, function (d, val) {\n var split = val.toString().split(','), valid = false;\n for (var i = 0; i < split.length; i++) {\n if (Math.abs((d.width / d.height) - upload.ratioToFloat(split[i])) < 0.0001) {\n valid = true;\n }\n }\n return valid;\n })));\n promises.push(upload.happyPromise(validateAsync('maxRatio', 'ratio.max', /image/,\n this.imageDimensions, function (d, val) {\n return (d.width / d.height) - upload.ratioToFloat(val) < 0.0001;\n })));\n promises.push(upload.happyPromise(validateAsync('minRatio', 'ratio.min', /image/,\n this.imageDimensions, function (d, val) {\n return (d.width / d.height) - upload.ratioToFloat(val) > -0.0001;\n })));\n promises.push(upload.happyPromise(validateAsync('maxDuration', 'duration.max', /audio|video/,\n this.mediaDuration, function (d, val) {\n return d <= upload.translateScalars(val);\n })));\n promises.push(upload.happyPromise(validateAsync('minDuration', 'duration.min', /audio|video/,\n this.mediaDuration, function (d, val) {\n return d >= upload.translateScalars(val);\n })));\n promises.push(upload.happyPromise(validateAsync('duration', null, /audio|video/,\n function (file, val) {\n return upload.emptyPromise(val);\n }, function (r) {\n return r;\n })));\n\n promises.push(upload.happyPromise(validateAsync('validateAsyncFn', null, null,\n function (file, val) {\n return val;\n }, function (r) {\n return r === true || r === null || r === '';\n })));\n\n return $q.all(promises).then(function () {\n deffer.resolve(ngModel, ngModel.$ngfValidations);\n });\n };\n\n upload.imageDimensions = function (file) {\n if (file.$ngfWidth && file.$ngfHeight) {\n var d = $q.defer();\n $timeout(function () {\n d.resolve({width: file.$ngfWidth, height: file.$ngfHeight});\n });\n return d.promise;\n }\n if (file.$ngfDimensionPromise) return file.$ngfDimensionPromise;\n\n var deferred = $q.defer();\n $timeout(function () {\n if (file.type.indexOf('image') !== 0) {\n deferred.reject('not image');\n return;\n }\n upload.dataUrl(file).then(function (dataUrl) {\n var img = angular.element('<img>').attr('src', dataUrl)\n .css('visibility', 'hidden').css('position', 'fixed')\n .css('max-width', 'none !important').css('max-height', 'none !important');\n\n function success() {\n var width = img[0].clientWidth;\n var height = img[0].clientHeight;\n img.remove();\n file.$ngfWidth = width;\n file.$ngfHeight = height;\n deferred.resolve({width: width, height: height});\n }\n\n function error() {\n img.remove();\n deferred.reject('load error');\n }\n\n img.on('load', success);\n img.on('error', error);\n var count = 0;\n\n function checkLoadError() {\n $timeout(function () {\n if (img[0].parentNode) {\n if (img[0].clientWidth) {\n success();\n } else if (count > 10) {\n error();\n } else {\n checkLoadError();\n }\n }\n }, 1000);\n }\n\n checkLoadError();\n\n angular.element(document.getElementsByTagName('body')[0]).append(img);\n }, function () {\n deferred.reject('load error');\n });\n });\n\n file.$ngfDimensionPromise = deferred.promise;\n file.$ngfDimensionPromise['finally'](function () {\n delete file.$ngfDimensionPromise;\n });\n return file.$ngfDimensionPromise;\n };\n\n upload.mediaDuration = function (file) {\n if (file.$ngfDuration) {\n var d = $q.defer();\n $timeout(function () {\n d.resolve(file.$ngfDuration);\n });\n return d.promise;\n }\n if (file.$ngfDurationPromise) return file.$ngfDurationPromise;\n\n var deferred = $q.defer();\n $timeout(function () {\n if (file.type.indexOf('audio') !== 0 && file.type.indexOf('video') !== 0) {\n deferred.reject('not media');\n return;\n }\n upload.dataUrl(file).then(function (dataUrl) {\n var el = angular.element(file.type.indexOf('audio') === 0 ? '<audio>' : '<video>')\n .attr('src', dataUrl).css('visibility', 'none').css('position', 'fixed');\n\n function success() {\n var duration = el[0].duration;\n file.$ngfDuration = duration;\n el.remove();\n deferred.resolve(duration);\n }\n\n function error() {\n el.remove();\n deferred.reject('load error');\n }\n\n el.on('loadedmetadata', success);\n el.on('error', error);\n var count = 0;\n\n function checkLoadError() {\n $timeout(function () {\n if (el[0].parentNode) {\n if (el[0].duration) {\n success();\n } else if (count > 10) {\n error();\n } else {\n checkLoadError();\n }\n }\n }, 1000);\n }\n\n checkLoadError();\n\n angular.element(document.body).append(el);\n }, function () {\n deferred.reject('load error');\n });\n });\n\n file.$ngfDurationPromise = deferred.promise;\n file.$ngfDurationPromise['finally'](function () {\n delete file.$ngfDurationPromise;\n });\n return file.$ngfDurationPromise;\n };\n return upload;\n}\n]);\n\nngFileUpload.service('UploadResize', ['UploadValidate', '$q', function (UploadValidate, $q) {\n var upload = UploadValidate;\n\n /**\n * Conserve aspect ratio of the original region. Useful when shrinking/enlarging\n * images to fit into a certain area.\n * Source: http://stackoverflow.com/a/14731922\n *\n * @param {Number} srcWidth Source area width\n * @param {Number} srcHeight Source area height\n * @param {Number} maxWidth Nestable area maximum available width\n * @param {Number} maxHeight Nestable area maximum available height\n * @return {Object} { width, height }\n */\n var calculateAspectRatioFit = function (srcWidth, srcHeight, maxWidth, maxHeight, centerCrop) {\n var ratio = centerCrop ? Math.max(maxWidth / srcWidth, maxHeight / srcHeight) :\n Math.min(maxWidth / srcWidth, maxHeight / srcHeight);\n return {\n width: srcWidth * ratio, height: srcHeight * ratio,\n marginX: srcWidth * ratio - maxWidth, marginY: srcHeight * ratio - maxHeight\n };\n };\n\n // Extracted from https://github.com/romelgomez/angular-firebase-image-upload/blob/master/app/scripts/fileUpload.js#L89\n var resize = function (imagen, width, height, quality, type, ratio, centerCrop, resizeIf) {\n var deferred = $q.defer();\n var canvasElement = document.createElement('canvas');\n var imageElement = document.createElement('img');\n\n imageElement.onload = function () {\n if (resizeIf != null && resizeIf(imageElement.width, imageElement.height) === false) {\n deferred.reject('resizeIf');\n return;\n }\n try {\n if (ratio) {\n var ratioFloat = upload.ratioToFloat(ratio);\n var imgRatio = imageElement.width / imageElement.height;\n if (imgRatio < ratioFloat) {\n width = imageElement.width;\n height = width / ratioFloat;\n } else {\n height = imageElement.height;\n width = height * ratioFloat;\n }\n }\n if (!width) {\n width = imageElement.width;\n }\n if (!height) {\n height = imageElement.height;\n }\n var dimensions = calculateAspectRatioFit(imageElement.width, imageElement.height, width, height, centerCrop);\n canvasElement.width = Math.min(dimensions.width, width);\n canvasElement.height = Math.min(dimensions.height, height);\n var context = canvasElement.getContext('2d');\n context.drawImage(imageElement,\n Math.min(0, -dimensions.marginX / 2), Math.min(0, -dimensions.marginY / 2),\n dimensions.width, dimensions.height);\n deferred.resolve(canvasElement.toDataURL(type || 'image/WebP', quality || 0.934));\n } catch (e) {\n deferred.reject(e);\n }\n };\n imageElement.onerror = function () {\n deferred.reject();\n };\n imageElement.src = imagen;\n return deferred.promise;\n };\n\n upload.dataUrltoBlob = function (dataurl, name, origSize) {\n var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],\n bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);\n while (n--) {\n u8arr[n] = bstr.charCodeAt(n);\n }\n var blob = new window.Blob([u8arr], {type: mime});\n blob.name = name;\n blob.$ngfOrigSize = origSize;\n return blob;\n };\n\n upload.isResizeSupported = function () {\n var elem = document.createElement('canvas');\n return window.atob && elem.getContext && elem.getContext('2d') && window.Blob;\n };\n\n if (upload.isResizeSupported()) {\n // add name getter to the blob constructor prototype\n Object.defineProperty(window.Blob.prototype, 'name', {\n get: function () {\n return this.$ngfName;\n },\n set: function (v) {\n this.$ngfName = v;\n },\n configurable: true\n });\n }\n\n upload.resize = function (file, width, height, quality, type, ratio, centerCrop, resizeIf, restoreExif) {\n if (file.type.indexOf('image') !== 0) return upload.emptyPromise(file);\n\n var deferred = $q.defer();\n upload.dataUrl(file, true).then(function (url) {\n resize(url, width, height, quality, type || file.type, ratio, centerCrop, resizeIf)\n .then(function (dataUrl) {\n if (file.type === 'image/jpeg' && restoreExif) {\n try {\n dataUrl = upload.restoreExif(url, dataUrl);\n } catch (e) {\n setTimeout(function () {throw e;}, 1);\n }\n }\n try {\n var blob = upload.dataUrltoBlob(dataUrl, file.name, file.size);\n deferred.resolve(blob);\n } catch (e) {\n deferred.reject(e);\n }\n }, function (r) {\n if (r === 'resizeIf') {\n deferred.resolve(file);\n }\n deferred.reject(r);\n });\n }, function (e) {\n deferred.reject(e);\n });\n return deferred.promise;\n };\n\n return upload;\n}]);\n\n(function () {\n ngFileUpload.directive('ngfDrop', ['$parse', '$timeout', '$location', 'Upload', '$http', '$q',\n function ($parse, $timeout, $location, Upload, $http, $q) {\n return {\n restrict: 'AEC',\n require: '?ngModel',\n link: function (scope, elem, attr, ngModel) {\n linkDrop(scope, elem, attr, ngModel, $parse, $timeout, $location, Upload, $http, $q);\n }\n };\n }]);\n\n ngFileUpload.directive('ngfNoFileDrop', function () {\n return function (scope, elem) {\n if (dropAvailable()) elem.css('display', 'none');\n };\n });\n\n ngFileUpload.directive('ngfDropAvailable', ['$parse', '$timeout', 'Upload', function ($parse, $timeout, Upload) {\n return function (scope, elem, attr) {\n if (dropAvailable()) {\n var model = $parse(Upload.attrGetter('ngfDropAvailable', attr));\n $timeout(function () {\n model(scope);\n if (model.assign) {\n model.assign(scope, true);\n }\n });\n }\n };\n }]);\n\n function linkDrop(scope, elem, attr, ngModel, $parse, $timeout, $location, upload, $http, $q) {\n var available = dropAvailable();\n\n var attrGetter = function (name, scope, params) {\n return upload.attrGetter(name, attr, scope, params);\n };\n\n if (attrGetter('dropAvailable')) {\n $timeout(function () {\n if (scope[attrGetter('dropAvailable')]) {\n scope[attrGetter('dropAvailable')].value = available;\n } else {\n scope[attrGetter('dropAvailable')] = available;\n }\n });\n }\n if (!available) {\n if (attrGetter('ngfHideOnDropNotAvailable', scope) === true) {\n elem.css('display', 'none');\n }\n return;\n }\n\n function isDisabled() {\n return elem.attr('disabled') || attrGetter('ngfDropDisabled', scope);\n }\n\n if (attrGetter('ngfSelect') == null) {\n upload.registerModelChangeValidator(ngModel, attr, scope);\n }\n\n var leaveTimeout = null;\n var stopPropagation = $parse(attrGetter('ngfStopPropagation'));\n var dragOverDelay = 1;\n var actualDragOverClass;\n\n elem[0].addEventListener('dragover', function (evt) {\n if (isDisabled() || !upload.shouldUpdateOn('drop', attr, scope)) return;\n evt.preventDefault();\n if (stopPropagation(scope)) evt.stopPropagation();\n // handling dragover events from the Chrome download bar\n if (navigator.userAgent.indexOf('Chrome') > -1) {\n var b = evt.dataTransfer.effectAllowed;\n evt.dataTransfer.dropEffect = ('move' === b || 'linkMove' === b) ? 'move' : 'copy';\n }\n $timeout.cancel(leaveTimeout);\n if (!actualDragOverClass) {\n actualDragOverClass = 'C';\n calculateDragOverClass(scope, attr, evt, function (clazz) {\n actualDragOverClass = clazz;\n elem.addClass(actualDragOverClass);\n attrGetter('ngfDrag', scope, {$isDragging: true, $class: actualDragOverClass, $event: evt});\n });\n }\n }, false);\n elem[0].addEventListener('dragenter', function (evt) {\n if (isDisabled() || !upload.shouldUpdateOn('drop', attr, scope)) return;\n evt.preventDefault();\n if (stopPropagation(scope)) evt.stopPropagation();\n }, false);\n elem[0].addEventListener('dragleave', function (evt) {\n if (isDisabled() || !upload.shouldUpdateOn('drop', attr, scope)) return;\n evt.preventDefault();\n if (stopPropagation(scope)) evt.stopPropagation();\n leaveTimeout = $timeout(function () {\n if (actualDragOverClass) elem.removeClass(actualDragOverClass);\n actualDragOverClass = null;\n attrGetter('ngfDrag', scope, {$isDragging: false, $event: evt});\n }, dragOverDelay || 100);\n }, false);\n elem[0].addEventListener('drop', function (evt) {\n if (isDisabled() || !upload.shouldUpdateOn('drop', attr, scope)) return;\n evt.preventDefault();\n if (stopPropagation(scope)) evt.stopPropagation();\n if (actualDragOverClass) elem.removeClass(actualDragOverClass);\n actualDragOverClass = null;\n var items = evt.dataTransfer.items;\n var html;\n try {\n html = evt.dataTransfer && evt.dataTransfer.getData && evt.dataTransfer.getData('text/html');\n } catch (e) {/* Fix IE11 that throw error calling getData */\n }\n\n extractFiles(items, evt.dataTransfer.files, attrGetter('ngfAllowDir', scope) !== false,\n attrGetter('multiple') || attrGetter('ngfMultiple', scope)).then(function (files) {\n if (files.length) {\n updateModel(files, evt);\n } else {\n extractFilesFromHtml('dropUrl', html).then(function (files) {\n updateModel(files, evt);\n });\n }\n });\n }, false);\n elem[0].addEventListener('paste', function (evt) {\n if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1 &&\n attrGetter('ngfEnableFirefoxPaste', scope)) {\n evt.preventDefault();\n }\n if (isDisabled() || !upload.shouldUpdateOn('paste', attr, scope)) return;\n var files = [];\n var clipboard = evt.clipboardData || evt.originalEvent.clipboardData;\n if (clipboard && clipboard.items) {\n for (var k = 0; k < clipboard.items.length; k++) {\n if (clipboard.items[k].type.indexOf('image') !== -1) {\n files.push(clipboard.items[k].getAsFile());\n }\n }\n }\n if (files.length) {\n updateModel(files, evt);\n } else {\n extractFilesFromHtml('pasteUrl', clipboard).then(function (files) {\n updateModel(files, evt);\n });\n }\n }, false);\n\n if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1 &&\n attrGetter('ngfEnableFirefoxPaste', scope)) {\n elem.attr('contenteditable', true);\n elem.on('keypress', function (e) {\n if (!e.metaKey && !e.ctrlKey) {\n e.preventDefault();\n }\n });\n }\n\n function updateModel(files, evt) {\n upload.updateModel(ngModel, attr, scope, attrGetter('ngfChange') || attrGetter('ngfDrop'), files, evt);\n }\n\n function extractFilesFromHtml(updateOn, html) {\n if (!upload.shouldUpdateOn(updateOn, attr, scope) || !html) return upload.rejectPromise([]);\n var urls = [];\n html.replace(/<(img src|img [^>]* src) *=\\\"([^\\\"]*)\\\"/gi, function (m, n, src) {\n urls.push(src);\n });\n var promises = [], files = [];\n if (urls.length) {\n angular.forEach(urls, function (url) {\n promises.push(upload.urlToBlob(url).then(function (blob) {\n files.push(blob);\n }));\n });\n var defer = $q.defer();\n $q.all(promises).then(function () {\n defer.resolve(files);\n }, function (e) {\n defer.reject(e);\n });\n return defer.promise;\n }\n return upload.emptyPromise();\n }\n\n function calculateDragOverClass(scope, attr, evt, callback) {\n var obj = attrGetter('ngfDragOverClass', scope, {$event: evt}), dClass = 'dragover';\n if (angular.isString(obj)) {\n dClass = obj;\n } else if (obj) {\n if (obj.delay) dragOverDelay = obj.delay;\n if (obj.accept || obj.reject) {\n var items = evt.dataTransfer.items;\n if (items == null || !items.length) {\n dClass = obj.accept;\n } else {\n var pattern = obj.pattern || attrGetter('ngfPattern', scope, {$event: evt});\n var len = items.length;\n while (len--) {\n if (!upload.validatePattern(items[len], pattern)) {\n dClass = obj.reject;\n break;\n } else {\n dClass = obj.accept;\n }\n }\n }\n }\n }\n callback(dClass);\n }\n\n function extractFiles(items, fileList, allowDir, multiple) {\n var maxFiles = upload.getValidationAttr(attr, scope, 'maxFiles') || Number.MAX_VALUE;\n var maxTotalSize = upload.getValidationAttr(attr, scope, 'maxTotalSize') || Number.MAX_VALUE;\n var includeDir = attrGetter('ngfIncludeDir', scope);\n var files = [], totalSize = 0;\n\n function traverseFileTree(entry, path) {\n var defer = $q.defer();\n if (entry != null) {\n if (entry.isDirectory) {\n var promises = [upload.emptyPromise()];\n if (includeDir) {\n var file = {type: 'directory'};\n file.name = file.path = (path || '') + entry.name + entry.name;\n files.push(file);\n }\n var dirReader = entry.createReader();\n var entries = [];\n var readEntries = function () {\n dirReader.readEntries(function (results) {\n try {\n if (!results.length) {\n angular.forEach(entries.slice(0), function (e) {\n if (files.length <= maxFiles && totalSize <= maxTotalSize) {\n promises.push(traverseFileTree(e, (path ? path : '') + entry.name + '/'));\n }\n });\n $q.all(promises).then(function () {\n defer.resolve();\n }, function (e) {\n defer.reject(e);\n });\n } else {\n entries = entries.concat(Array.prototype.slice.call(results || [], 0));\n readEntries();\n }\n } catch (e) {\n defer.reject(e);\n }\n }, function (e) {\n defer.reject(e);\n });\n };\n readEntries();\n } else {\n entry.file(function (file) {\n try {\n file.path = (path ? path : '') + file.name;\n if (includeDir) {\n file = upload.rename(file, file.path);\n }\n files.push(file);\n totalSize += file.size;\n defer.resolve();\n } catch (e) {\n defer.reject(e);\n }\n }, function (e) {\n defer.reject(e);\n });\n }\n }\n return defer.promise;\n }\n\n var promises = [upload.emptyPromise()];\n\n if (items && items.length > 0 && $location.protocol() !== 'file') {\n for (var i = 0; i < items.length; i++) {\n if (items[i].webkitGetAsEntry && items[i].webkitGetAsEntry() && items[i].webkitGetAsEntry().isDirectory) {\n var entry = items[i].webkitGetAsEntry();\n if (entry.isDirectory && !allowDir) {\n continue;\n }\n if (entry != null) {\n promises.push(traverseFileTree(entry));\n }\n } else {\n var f = items[i].getAsFile();\n if (f != null) {\n files.push(f);\n totalSize += f.size;\n }\n }\n if (files.length > maxFiles || totalSize > maxTotalSize ||\n (!multiple && files.length > 0)) break;\n }\n } else {\n if (fileList != null) {\n for (var j = 0; j < fileList.length; j++) {\n var file = fileList.item(j);\n if (file.type || file.size > 0) {\n files.push(file);\n totalSize += file.size;\n }\n if (files.length > maxFiles || totalSize > maxTotalSize ||\n (!multiple && files.length > 0)) break;\n }\n }\n }\n\n var defer = $q.defer();\n $q.all(promises).then(function () {\n if (!multiple && !includeDir && files.length) {\n var i = 0;\n while (files[i] && files[i].type === 'directory') i++;\n defer.resolve([files[i]]);\n } else {\n defer.resolve(files);\n }\n }, function (e) {\n defer.reject(e);\n });\n\n return defer.promise;\n }\n }\n\n function dropAvailable() {\n var div = document.createElement('div');\n return ('draggable' in div) && ('ondrop' in div) && !/Edge\\/12./i.test(navigator.userAgent);\n }\n\n})();\n\n// customized version of https://github.com/exif-js/exif-js\nngFileUpload.service('UploadExif', ['UploadResize', '$q', function (UploadResize, $q) {\n var upload = UploadResize;\n\n upload.isExifSupported = function () {\n return window.FileReader && new FileReader().readAsArrayBuffer && upload.isResizeSupported();\n };\n\n function applyTransform(ctx, orientation, width, height) {\n switch (orientation) {\n case 2:\n return ctx.transform(-1, 0, 0, 1, width, 0);\n case 3:\n return ctx.transform(-1, 0, 0, -1, width, height);\n case 4:\n return ctx.transform(1, 0, 0, -1, 0, height);\n case 5:\n return ctx.transform(0, 1, 1, 0, 0, 0);\n case 6:\n return ctx.transform(0, 1, -1, 0, height, 0);\n case 7:\n return ctx.transform(0, -1, -1, 0, height, width);\n case 8:\n return ctx.transform(0, -1, 1, 0, 0, width);\n }\n }\n\n upload.readOrientation = function (file) {\n var defer = $q.defer();\n var reader = new FileReader();\n var slicedFile = file.slice ? file.slice(0, 64 * 1024) : file;\n reader.readAsArrayBuffer(slicedFile);\n reader.onerror = function (e) {\n return defer.reject(e);\n };\n reader.onload = function (e) {\n var result = {orientation: 1};\n var view = new DataView(this.result);\n if (view.getUint16(0, false) !== 0xFFD8) return defer.resolve(result);\n\n var length = view.byteLength,\n offset = 2;\n while (offset < length) {\n var marker = view.getUint16(offset, false);\n offset += 2;\n if (marker === 0xFFE1) {\n if (view.getUint32(offset += 2, false) !== 0x45786966) return defer.resolve(result);\n\n var little = view.getUint16(offset += 6, false) === 0x4949;\n offset += view.getUint32(offset + 4, little);\n var tags = view.getUint16(offset, little);\n offset += 2;\n for (var i = 0; i < tags; i++)\n if (view.getUint16(offset + (i * 12), little) === 0x0112) {\n var orientation = view.getUint16(offset + (i * 12) + 8, little);\n if (orientation >= 2 && orientation <= 8) {\n view.setUint16(offset + (i * 12) + 8, 1, little);\n result.fixedArrayBuffer = e.target.result;\n }\n result.orientation = orientation;\n return defer.resolve(result);\n }\n } else if ((marker & 0xFF00) !== 0xFF00) break;\n else offset += view.getUint16(offset, false);\n }\n return defer.resolve(result);\n };\n return defer.promise;\n };\n\n function arrayBufferToBase64(buffer) {\n var binary = '';\n var bytes = new Uint8Array(buffer);\n var len = bytes.byteLength;\n for (var i = 0; i < len; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return window.btoa(binary);\n }\n\n upload.applyExifRotation = function (file) {\n if (file.type.indexOf('image/jpeg') !== 0) {\n return upload.emptyPromise(file);\n }\n\n var deferred = $q.defer();\n upload.readOrientation(file).then(function (result) {\n if (result.orientation < 2 || result.orientation > 8) {\n return deferred.resolve(file);\n }\n upload.dataUrl(file, true).then(function (url) {\n var canvas = document.createElement('canvas');\n var img = document.createElement('img');\n\n img.onload = function () {\n try {\n canvas.width = result.orientation > 4 ? img.height : img.width;\n canvas.height = result.orientation > 4 ? img.width : img.height;\n var ctx = canvas.getContext('2d');\n applyTransform(ctx, result.orientation, img.width, img.height);\n ctx.drawImage(img, 0, 0);\n var dataUrl = canvas.toDataURL(file.type || 'image/WebP', 0.934);\n dataUrl = upload.restoreExif(arrayBufferToBase64(result.fixedArrayBuffer), dataUrl);\n var blob = upload.dataUrltoBlob(dataUrl, file.name);\n deferred.resolve(blob);\n } catch (e) {\n return deferred.reject(e);\n }\n };\n img.onerror = function () {\n deferred.reject();\n };\n img.src = url;\n }, function (e) {\n deferred.reject(e);\n });\n }, function (e) {\n deferred.reject(e);\n });\n return deferred.promise;\n };\n\n upload.restoreExif = function (orig, resized) {\n var ExifRestorer = {};\n\n ExifRestorer.KEY_STR = 'ABCDEFGHIJKLMNOP' +\n 'QRSTUVWXYZabcdef' +\n 'ghijklmnopqrstuv' +\n 'wxyz0123456789+/' +\n '=';\n\n ExifRestorer.encode64 = function (input) {\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 if (origFileBase64.match('data:image/jpeg;base64,')) {\n origFileBase64 = origFileBase64.replace('data:image/jpeg;base64,', '');\n }\n\n var rawImage = this.decode64(origFileBase64);\n var segments = this.slice2Segments(rawImage);\n\n var image = this.exifManipulation(resizedFileBase64, segments);\n\n return 'data:image/jpeg;base64,' + this.encode64(image);\n };\n\n\n ExifRestorer.exifManipulation = function (resizedFileBase64, segments) {\n var exifArray = this.getExifArray(segments),\n newImageArray = this.insertExif(resizedFileBase64, exifArray);\n return new Uint8Array(newImageArray);\n };\n\n\n ExifRestorer.getExifArray = function (segments) {\n var seg;\n for (var x = 0; x < segments.length; x++) {\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 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 ExifRestorer.slice2Segments = function (rawImageArray) {\n var head = 0,\n segments = [];\n\n while (1) {\n if (rawImageArray[head] === 255 & rawImageArray[head + 1] === 218) {\n break;\n }\n if (rawImageArray[head] === 255 & rawImageArray[head + 1] === 216) {\n head += 2;\n }\n else {\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) {\n break;\n }\n }\n\n return segments;\n };\n\n\n ExifRestorer.decode64 = function (input) {\n var 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 console.log('There were invalid base64 characters in the input text.\\n' +\n 'Valid base64 characters are A-Z, a-z, 0-9, ' + ', ' / ',and \"=\"\\n' +\n 'Expect errors in decoding.');\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 return ExifRestorer.restore(orig, resized); //<= EXIF\n };\n\n return upload;\n}]);\n\n","/*! ng-dialog - v0.6.3 (https://github.com/likeastore/ngDialog) */\n!function(a,b){\"undefined\"!=typeof module&&module.exports?(b(\"undefined\"==typeof angular?require(\"angular\"):angular),module.exports=\"ngDialog\"):\"function\"==typeof define&&define.amd?define([\"angular\"],b):b(a.angular)}(this,function(a){\"use strict\";var b=a.module(\"ngDialog\",[]),c=a.element,d=a.isDefined,e=(document.body||document.documentElement).style,f=d(e.animation)||d(e.WebkitAnimation)||d(e.MozAnimation)||d(e.MsAnimation)||d(e.OAnimation),g=\"animationend webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend\",h=\"a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]\",i=\"ngdialog-disabled-animation\",j={html:!1,body:!1},k={},l=[],m=!1,n=!1;return b.provider(\"ngDialog\",function(){var b=this.defaults={className:\"ngdialog-theme-default\",appendClassName:\"\",disableAnimation:!1,plain:!1,showClose:!0,closeByDocument:!0,closeByEscape:!0,closeByNavigation:!1,appendTo:!1,preCloseCallback:!1,overlay:!0,cache:!0,trapFocus:!0,preserveFocus:!0,ariaAuto:!0,ariaRole:null,ariaLabelledById:null,ariaLabelledBySelector:null,ariaDescribedById:null,ariaDescribedBySelector:null,bodyClassName:\"ngdialog-open\",width:null,height:null};this.setForceHtmlReload=function(a){j.html=a||!1},this.setForceBodyReload=function(a){j.body=a||!1},this.setDefaults=function(c){a.extend(b,c)},this.setOpenOnePerName=function(a){n=a||!1};var d,e=0,o=0,p={};this.$get=[\"$document\",\"$templateCache\",\"$compile\",\"$q\",\"$http\",\"$rootScope\",\"$timeout\",\"$window\",\"$controller\",\"$injector\",function(q,r,s,t,u,v,w,x,y,z){var A=[],B={onDocumentKeydown:function(a){27===a.keyCode&&C.close(\"$escape\")},activate:function(a){var b=a.data(\"$ngDialogOptions\");b.trapFocus&&(a.on(\"keydown\",B.onTrapFocusKeydown),A.body.on(\"keydown\",B.onTrapFocusKeydown))},deactivate:function(a){a.off(\"keydown\",B.onTrapFocusKeydown),A.body.off(\"keydown\",B.onTrapFocusKeydown)},deactivateAll:function(b){a.forEach(b,function(b){var c=a.element(b);B.deactivate(c)})},setBodyPadding:function(a){var b=parseInt(A.body.css(\"padding-right\")||0,10);A.body.css(\"padding-right\",b+a+\"px\"),A.body.data(\"ng-dialog-original-padding\",b),v.$broadcast(\"ngDialog.setPadding\",a)},resetBodyPadding:function(){var a=A.body.data(\"ng-dialog-original-padding\");a?A.body.css(\"padding-right\",a+\"px\"):A.body.css(\"padding-right\",\"\"),v.$broadcast(\"ngDialog.setPadding\",0)},performCloseDialog:function(a,b){var c=a.data(\"$ngDialogOptions\"),e=a.attr(\"id\"),h=k[e];if(h){if(\"undefined\"!=typeof x.Hammer){var i=h.hammerTime;i.off(\"tap\",d),i.destroy&&i.destroy(),delete h.hammerTime}else a.unbind(\"click\");1===o&&A.body.unbind(\"keydown\",B.onDocumentKeydown),a.hasClass(\"ngdialog-closing\")||(o-=1);var j=a.data(\"$ngDialogPreviousFocus\");j&&j.focus&&j.focus(),v.$broadcast(\"ngDialog.closing\",a,b),o=o<0?0:o,f&&!c.disableAnimation?(h.$destroy(),a.unbind(g).bind(g,function(){B.closeDialogElement(a,b)}).addClass(\"ngdialog-closing\")):(h.$destroy(),B.closeDialogElement(a,b)),p[e]&&(p[e].resolve({id:e,value:b,$dialog:a,remainingDialogs:o}),delete p[e]),k[e]&&delete k[e],l.splice(l.indexOf(e),1),l.length||(A.body.unbind(\"keydown\",B.onDocumentKeydown),m=!1)}},closeDialogElement:function(a,b){var c=a.data(\"$ngDialogOptions\");a.remove(),0===o&&(A.html.removeClass(c.bodyClassName),A.body.removeClass(c.bodyClassName),B.resetBodyPadding()),v.$broadcast(\"ngDialog.closed\",a,b)},closeDialog:function(b,c){var d=b.data(\"$ngDialogPreCloseCallback\");if(d&&a.isFunction(d)){var e=d.call(b,c);if(a.isObject(e))e.closePromise?e.closePromise.then(function(){B.performCloseDialog(b,c)},function(){return!1}):e.then(function(){B.performCloseDialog(b,c)},function(){return!1});else{if(e===!1)return!1;B.performCloseDialog(b,c)}}else B.performCloseDialog(b,c)},onTrapFocusKeydown:function(b){var c,d=a.element(b.currentTarget);if(d.hasClass(\"ngdialog\"))c=d;else if(c=B.getActiveDialog(),null===c)return;var e=9===b.keyCode,f=b.shiftKey===!0;e&&B.handleTab(c,b,f)},handleTab:function(a,b,c){var d=B.getFocusableElements(a);if(0===d.length)return void(document.activeElement&&document.activeElement.blur&&document.activeElement.blur());var e=document.activeElement,f=Array.prototype.indexOf.call(d,e),g=f===-1,h=0===f,i=f===d.length-1,j=!1;c?(g||h)&&(d[d.length-1].focus(),j=!0):(g||i)&&(d[0].focus(),j=!0),j&&(b.preventDefault(),b.stopPropagation())},autoFocus:function(a){var b=a[0],d=b.querySelector(\"*[autofocus]\");if(null===d||(d.focus(),document.activeElement!==d)){var e=B.getFocusableElements(a);if(e.length>0)return void e[0].focus();var f=B.filterVisibleElements(b.querySelectorAll(\"h1,h2,h3,h4,h5,h6,p,span\"));if(f.length>0){var g=f[0];c(g).attr(\"tabindex\",\"-1\").css(\"outline\",\"0\"),g.focus()}}},getFocusableElements:function(a){var b=a[0],c=b.querySelectorAll(h),d=B.filterTabbableElements(c);return B.filterVisibleElements(d)},filterTabbableElements:function(a){for(var b=[],d=0;d<a.length;d++){var e=a[d];\"-1\"!==c(e).attr(\"tabindex\")&&b.push(e)}return b},filterVisibleElements:function(a){for(var b=[],c=0;c<a.length;c++){var d=a[c];(d.offsetWidth>0||d.offsetHeight>0)&&b.push(d)}return b},getActiveDialog:function(){var a=document.querySelectorAll(\".ngdialog\");return 0===a.length?null:c(a[a.length-1])},applyAriaAttributes:function(a,b){if(b.ariaAuto){if(!b.ariaRole){var c=B.getFocusableElements(a).length>0?\"dialog\":\"alertdialog\";b.ariaRole=c}b.ariaLabelledBySelector||(b.ariaLabelledBySelector=\"h1,h2,h3,h4,h5,h6\"),b.ariaDescribedBySelector||(b.ariaDescribedBySelector=\"article,section,p\")}b.ariaRole&&a.attr(\"role\",b.ariaRole),B.applyAriaAttribute(a,\"aria-labelledby\",b.ariaLabelledById,b.ariaLabelledBySelector),B.applyAriaAttribute(a,\"aria-describedby\",b.ariaDescribedById,b.ariaDescribedBySelector)},applyAriaAttribute:function(a,b,d,e){if(d&&a.attr(b,d),e){var f=a.attr(\"id\"),g=a[0].querySelector(e);if(!g)return;var h=f+\"-\"+b;return c(g).attr(\"id\",h),a.attr(b,h),h}},detectUIRouter:function(){try{return a.module(\"ui.router\"),!0}catch(b){return!1}},getRouterLocationEventName:function(){return B.detectUIRouter()?\"$stateChangeStart\":\"$locationChangeStart\"}},C={__PRIVATE__:B,open:function(f){function g(a,b){return v.$broadcast(\"ngDialog.templateLoading\",a),u.get(a,b||{}).then(function(b){return v.$broadcast(\"ngDialog.templateLoaded\",a),b.data||\"\"})}function h(b){return b?a.isString(b)&&q.plain?b:\"boolean\"!=typeof q.cache||q.cache?g(b,{cache:r}):g(b,{cache:!1}):\"Empty template\"}var j=null;if(f=f||{},!(n&&f.name&&(j=f.name.toLowerCase().replace(/\\s/g,\"-\")+\"-dialog\",this.isOpen(j)))){var q=a.copy(b),D=++e;j=j||\"ngdialog\"+D,l.push(j),\"undefined\"!=typeof q.data&&(\"undefined\"==typeof f.data&&(f.data={}),f.data=a.merge(a.copy(q.data),f.data)),a.extend(q,f);var E;p[j]=E=t.defer();var F;k[j]=F=a.isObject(q.scope)?q.scope.$new():v.$new();var G,H,I,J=a.extend({},q.resolve);return a.forEach(J,function(b,c){J[c]=a.isString(b)?z.get(b):z.invoke(b,null,null,c)}),t.all({template:h(q.template||q.templateUrl),locals:t.all(J)}).then(function(b){var e=b.template,f=b.locals;q.showClose&&(e+='<div class=\"ngdialog-close\"></div>');var g=q.overlay?\"\":\" ngdialog-no-overlay\";if(G=c('<div id=\"'+j+'\" class=\"ngdialog'+g+'\"></div>'),G.html(q.overlay?'<div class=\"ngdialog-overlay\"></div><div class=\"ngdialog-content\" role=\"document\">'+e+\"</div>\":'<div class=\"ngdialog-content\" role=\"document\">'+e+\"</div>\"),G.data(\"$ngDialogOptions\",q),F.ngDialogId=j,q.data&&a.isString(q.data)){var h=q.data.replace(/^\\s*/,\"\")[0];F.ngDialogData=\"{\"===h||\"[\"===h?a.fromJson(q.data):new String(q.data),F.ngDialogData.ngDialogId=j}else q.data&&a.isObject(q.data)&&(F.ngDialogData=q.data,F.ngDialogData.ngDialogId=j);if(q.className&&G.addClass(q.className),q.appendClassName&&G.addClass(q.appendClassName),q.width&&(I=G[0].querySelector(\".ngdialog-content\"),a.isString(q.width)?I.style.width=q.width:I.style.width=q.width+\"px\"),q.height&&(I=G[0].querySelector(\".ngdialog-content\"),a.isString(q.height)?I.style.height=q.height:I.style.height=q.height+\"px\"),q.disableAnimation&&G.addClass(i),H=q.appendTo&&a.isString(q.appendTo)?a.element(document.querySelector(q.appendTo)):A.body,B.applyAriaAttributes(G,q),q.preCloseCallback){var k;a.isFunction(q.preCloseCallback)?k=q.preCloseCallback:a.isString(q.preCloseCallback)&&F&&(a.isFunction(F[q.preCloseCallback])?k=F[q.preCloseCallback]:F.$parent&&a.isFunction(F.$parent[q.preCloseCallback])?k=F.$parent[q.preCloseCallback]:v&&a.isFunction(v[q.preCloseCallback])&&(k=v[q.preCloseCallback])),k&&G.data(\"$ngDialogPreCloseCallback\",k)}if(F.closeThisDialog=function(a){B.closeDialog(G,a)},q.controller&&(a.isString(q.controller)||a.isArray(q.controller)||a.isFunction(q.controller))){var l;q.controllerAs&&a.isString(q.controllerAs)&&(l=q.controllerAs);var n=y(q.controller,a.extend(f,{$scope:F,$element:G}),!0,l);q.bindToController&&a.extend(n.instance,{ngDialogId:F.ngDialogId,ngDialogData:F.ngDialogData,closeThisDialog:F.closeThisDialog,confirm:F.confirm}),\"function\"==typeof n?G.data(\"$ngDialogControllerController\",n()):G.data(\"$ngDialogControllerController\",n)}if(w(function(){var a=document.querySelectorAll(\".ngdialog\");B.deactivateAll(a),s(G)(F);var b=x.innerWidth-A.body.prop(\"clientWidth\");A.html.addClass(q.bodyClassName),A.body.addClass(q.bodyClassName);var c=b-(x.innerWidth-A.body.prop(\"clientWidth\"));c>0&&B.setBodyPadding(c),H.append(G),B.activate(G),q.trapFocus&&B.autoFocus(G),q.name?v.$broadcast(\"ngDialog.opened\",{dialog:G,name:q.name}):v.$broadcast(\"ngDialog.opened\",G)}),m||(A.body.bind(\"keydown\",B.onDocumentKeydown),m=!0),q.closeByNavigation){var p=B.getRouterLocationEventName();v.$on(p,function(a){B.closeDialog(G)===!1&&a.preventDefault()})}if(q.preserveFocus&&G.data(\"$ngDialogPreviousFocus\",document.activeElement),d=function(a){var b=!!q.closeByDocument&&c(a.target).hasClass(\"ngdialog-overlay\"),d=c(a.target).hasClass(\"ngdialog-close\");(b||d)&&C.close(G.attr(\"id\"),d?\"$closeButton\":\"$document\")},\"undefined\"!=typeof x.Hammer){var r=F.hammerTime=x.Hammer(G[0]);r.on(\"tap\",d)}else G.bind(\"click\",d);return o+=1,C}),{id:j,closePromise:E.promise,close:function(a){B.closeDialog(G,a)}}}},openConfirm:function(d){var e=t.defer(),f=a.copy(b);d=d||{},\"undefined\"!=typeof f.data&&(\"undefined\"==typeof d.data&&(d.data={}),d.data=a.merge(a.copy(f.data),d.data)),a.extend(f,d),f.scope=a.isObject(f.scope)?f.scope.$new():v.$new(),f.scope.confirm=function(a){e.resolve(a);var b=c(document.getElementById(g.id));B.performCloseDialog(b,a)};var g=C.open(f);if(g)return g.closePromise.then(function(a){return a?e.reject(a.value):e.reject()}),e.promise},isOpen:function(a){var b=c(document.getElementById(a));return b.length>0},close:function(a,b){var d=c(document.getElementById(a));if(d.length)B.closeDialog(d,b);else if(\"$escape\"===a){var e=l[l.length-1];d=c(document.getElementById(e)),d.data(\"$ngDialogOptions\").closeByEscape&&B.closeDialog(d,\"$escape\")}else C.closeAll(b);return C},closeAll:function(a){for(var b=document.querySelectorAll(\".ngdialog\"),d=b.length-1;d>=0;d--){var e=b[d];B.closeDialog(c(e),a)}},getOpenDialogs:function(){return l},getDefaults:function(){return b}};return a.forEach([\"html\",\"body\"],function(a){if(A[a]=q.find(a),j[a]){var b=B.getRouterLocationEventName();v.$on(b,function(){A[a]=q.find(a)})}}),C}]}),b.directive(\"ngDialog\",[\"ngDialog\",function(b){return{restrict:\"A\",scope:{ngDialogScope:\"=\"},link:function(c,d,e){d.on(\"click\",function(d){d.preventDefault();var f=a.isDefined(c.ngDialogScope)?c.ngDialogScope:\"noScope\";a.isDefined(e.ngDialogClosePrevious)&&b.close(e.ngDialogClosePrevious);var g=b.getDefaults();b.open({template:e.ngDialog,className:e.ngDialogClass||g.className,appendClassName:e.ngDialogAppendClass,controller:e.ngDialogController,controllerAs:e.ngDialogControllerAs,bindToController:e.ngDialogBindToController,scope:f,data:e.ngDialogData,showClose:\"false\"!==e.ngDialogShowClose&&(\"true\"===e.ngDialogShowClose||g.showClose),closeByDocument:\"false\"!==e.ngDialogCloseByDocument&&(\"true\"===e.ngDialogCloseByDocument||g.closeByDocument),closeByEscape:\"false\"!==e.ngDialogCloseByEscape&&(\"true\"===e.ngDialogCloseByEscape||g.closeByEscape),overlay:\"false\"!==e.ngDialogOverlay&&(\"true\"===e.ngDialogOverlay||g.overlay),preCloseCallback:e.ngDialogPreCloseCallback||g.preCloseCallback,bodyClassName:e.ngDialogBodyClass||g.bodyClassName})})}}}]),b});"]}