HEX
Server: Microsoft-IIS/8.5
System: Windows NT YDAWBH120 6.3 build 9600 (Windows Server 2012 R2 Standard Edition) AMD64
User: tentjecom_web (0)
PHP: 7.4.14
Disabled: NONE
Upload Files
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});"]}