cloudinary 1.9.1 → 1.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. checksums.yaml +5 -5
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +42 -0
  3. data/.github/ISSUE_TEMPLATE/feature_request.md +21 -0
  4. data/.github/pull_request_template.md +24 -0
  5. data/.gitignore +7 -1
  6. data/.travis.yml +15 -8
  7. data/CHANGELOG.md +261 -0
  8. data/README.md +3 -0
  9. data/Rakefile +3 -45
  10. data/cloudinary.gemspec +27 -20
  11. data/lib/active_storage/blob_key.rb +20 -0
  12. data/lib/active_storage/service/cloudinary_service.rb +249 -0
  13. data/lib/cloudinary.rb +53 -63
  14. data/lib/cloudinary/account_api.rb +231 -0
  15. data/lib/cloudinary/account_config.rb +30 -0
  16. data/lib/cloudinary/api.rb +228 -71
  17. data/lib/cloudinary/auth_token.rb +10 -4
  18. data/lib/cloudinary/base_api.rb +79 -0
  19. data/lib/cloudinary/base_config.rb +70 -0
  20. data/lib/cloudinary/cache.rb +38 -0
  21. data/lib/cloudinary/cache/breakpoints_cache.rb +31 -0
  22. data/lib/cloudinary/cache/key_value_cache_adapter.rb +25 -0
  23. data/lib/cloudinary/cache/rails_cache_adapter.rb +34 -0
  24. data/lib/cloudinary/cache/storage/rails_cache_storage.rb +5 -0
  25. data/lib/cloudinary/carrier_wave.rb +4 -2
  26. data/lib/cloudinary/carrier_wave/remote.rb +3 -2
  27. data/lib/cloudinary/carrier_wave/storage.rb +2 -1
  28. data/lib/cloudinary/{controller.rb → cloudinary_controller.rb} +3 -5
  29. data/lib/cloudinary/config.rb +43 -0
  30. data/lib/cloudinary/helper.rb +77 -7
  31. data/lib/cloudinary/migrator.rb +3 -1
  32. data/lib/cloudinary/railtie.rb +7 -3
  33. data/lib/cloudinary/responsive.rb +111 -0
  34. data/lib/cloudinary/uploader.rb +67 -15
  35. data/lib/cloudinary/utils.rb +324 -54
  36. data/lib/cloudinary/version.rb +1 -1
  37. data/lib/cloudinary/video_helper.rb +96 -22
  38. data/lib/tasks/cloudinary/fetch_assets.rake +48 -0
  39. data/lib/tasks/{cloudinary.rake → cloudinary/sync_static.rake} +0 -0
  40. data/tools/allocate_test_cloud.sh +9 -0
  41. data/tools/get_test_cloud.sh +9 -0
  42. data/tools/update_version +220 -0
  43. data/vendor/assets/javascripts/cloudinary/jquery.cloudinary.js +51 -13
  44. data/vendor/assets/javascripts/cloudinary/jquery.fileupload.js +24 -4
  45. data/vendor/assets/javascripts/cloudinary/jquery.ui.widget.js +741 -561
  46. data/vendor/assets/javascripts/cloudinary/load-image.all.min.js +1 -1
  47. metadata +92 -67
  48. data/spec/access_control_spec.rb +0 -99
  49. data/spec/api_spec.rb +0 -545
  50. data/spec/archive_spec.rb +0 -129
  51. data/spec/auth_token_spec.rb +0 -79
  52. data/spec/cloudinary_helper_spec.rb +0 -190
  53. data/spec/cloudinary_spec.rb +0 -32
  54. data/spec/data/sync_static/app/assets/javascripts/1.coffee +0 -1
  55. data/spec/data/sync_static/app/assets/javascripts/1.js +0 -1
  56. data/spec/data/sync_static/app/assets/stylesheets/1.css +0 -3
  57. data/spec/docx.docx +0 -0
  58. data/spec/favicon.ico +0 -0
  59. data/spec/logo.png +0 -0
  60. data/spec/rake_spec.rb +0 -160
  61. data/spec/sample_asset_file.tsv +0 -4
  62. data/spec/search_spec.rb +0 -109
  63. data/spec/spec_helper.rb +0 -245
  64. data/spec/storage_spec.rb +0 -44
  65. data/spec/streaminig_profiles_api_spec.rb +0 -74
  66. data/spec/support/helpers/temp_file_helpers.rb +0 -22
  67. data/spec/support/shared_contexts/rake.rb +0 -19
  68. data/spec/uploader_spec.rb +0 -363
  69. data/spec/utils_methods_spec.rb +0 -54
  70. data/spec/utils_spec.rb +0 -906
  71. data/spec/video_tag_spec.rb +0 -251
  72. data/spec/video_url_spec.rb +0 -164
@@ -1,2 +1,2 @@
1
- !function(e){"use strict";function t(e,i,a){var o,n=document.createElement("img");return n.onerror=function(o){return t.onerror(n,o,e,i,a)},n.onload=function(o){return t.onload(n,o,e,i,a)},"string"==typeof e?(t.fetchBlob(e,function(i){i?(e=i,o=t.createObjectURL(e)):(o=e,a&&a.crossOrigin&&(n.crossOrigin=a.crossOrigin)),n.src=o},a),n):t.isInstanceOf("Blob",e)||t.isInstanceOf("File",e)?(o=n._objectURL=t.createObjectURL(e))?(n.src=o,n):t.readFile(e,function(e){var t=e.target;t&&t.result?n.src=t.result:i&&i(e)}):void 0}function i(e,i){!e._objectURL||i&&i.noRevoke||(t.revokeObjectURL(e._objectURL),delete e._objectURL)}var a=e.createObjectURL&&e||e.URL&&URL.revokeObjectURL&&URL||e.webkitURL&&webkitURL;t.fetchBlob=function(e,t,i){t()},t.isInstanceOf=function(e,t){return Object.prototype.toString.call(t)==="[object "+e+"]"},t.transform=function(e,t,i,a,o){i(e,o)},t.onerror=function(e,t,a,o,n){i(e,n),o&&o.call(e,t)},t.onload=function(e,a,o,n,r){i(e,r),n&&t.transform(e,r,n,o,{})},t.createObjectURL=function(e){return!!a&&a.createObjectURL(e)},t.revokeObjectURL=function(e){return!!a&&a.revokeObjectURL(e)},t.readFile=function(t,i,a){if(e.FileReader){var o=new FileReader;if(o.onload=o.onerror=i,a=a||"readAsDataURL",o[a])return o[a](t),o}return!1},"function"==typeof define&&define.amd?define(function(){return t}):"object"==typeof module&&module.exports?module.exports=t:e.loadImage=t}("undefined"!=typeof window&&window||this),function(e){"use strict";"function"==typeof define&&define.amd?define(["./load-image"],e):e("object"==typeof module&&module.exports?require("./load-image"):window.loadImage)}(function(e){"use strict";var t=e.transform;e.transform=function(i,a,o,n,r){t.call(e,e.scale(i,a,r),a,o,n,r)},e.transformCoordinates=function(){},e.getTransformedOptions=function(e,t){var i,a,o,n,r=t.aspectRatio;if(!r)return t;i={};for(a in t)t.hasOwnProperty(a)&&(i[a]=t[a]);return i.crop=!0,o=e.naturalWidth||e.width,n=e.naturalHeight||e.height,o/n>r?(i.maxWidth=n*r,i.maxHeight=n):(i.maxWidth=o,i.maxHeight=o/r),i},e.renderImageToCanvas=function(e,t,i,a,o,n,r,s,l,d){return e.getContext("2d").drawImage(t,i,a,o,n,r,s,l,d),e},e.hasCanvasOption=function(e){return e.canvas||e.crop||!!e.aspectRatio},e.scale=function(t,i,a){function o(){var e=Math.max((l||v)/v,(d||P)/P);e>1&&(v*=e,P*=e)}function n(){var e=Math.min((r||v)/v,(s||P)/P);e<1&&(v*=e,P*=e)}i=i||{};var r,s,l,d,c,u,f,g,h,m,p,S=document.createElement("canvas"),b=t.getContext||e.hasCanvasOption(i)&&S.getContext,y=t.naturalWidth||t.width,x=t.naturalHeight||t.height,v=y,P=x;if(b&&(f=(i=e.getTransformedOptions(t,i,a)).left||0,g=i.top||0,i.sourceWidth?(c=i.sourceWidth,void 0!==i.right&&void 0===i.left&&(f=y-c-i.right)):c=y-f-(i.right||0),i.sourceHeight?(u=i.sourceHeight,void 0!==i.bottom&&void 0===i.top&&(g=x-u-i.bottom)):u=x-g-(i.bottom||0),v=c,P=u),r=i.maxWidth,s=i.maxHeight,l=i.minWidth,d=i.minHeight,b&&r&&s&&i.crop?(v=r,P=s,(p=c/u-r/s)<0?(u=s*c/r,void 0===i.top&&void 0===i.bottom&&(g=(x-u)/2)):p>0&&(c=r*u/s,void 0===i.left&&void 0===i.right&&(f=(y-c)/2))):((i.contain||i.cover)&&(l=r=r||l,d=s=s||d),i.cover?(n(),o()):(o(),n())),b){if((h=i.pixelRatio)>1&&(S.style.width=v+"px",S.style.height=P+"px",v*=h,P*=h,S.getContext("2d").scale(h,h)),(m=i.downsamplingRatio)>0&&m<1&&v<c&&P<u)for(;c*m>v;)S.width=c*m,S.height=u*m,e.renderImageToCanvas(S,t,f,g,c,u,0,0,S.width,S.height),f=0,g=0,c=S.width,u=S.height,(t=document.createElement("canvas")).width=c,t.height=u,e.renderImageToCanvas(t,S,0,0,c,u,0,0,c,u);return S.width=v,S.height=P,e.transformCoordinates(S,i),e.renderImageToCanvas(S,t,f,g,c,u,0,0,v,P)}return t.width=v,t.height=P,t}}),function(e){"use strict";"function"==typeof define&&define.amd?define(["./load-image"],e):e("object"==typeof module&&module.exports?require("./load-image"):window.loadImage)}(function(e){"use strict";var t="undefined"!=typeof Blob&&(Blob.prototype.slice||Blob.prototype.webkitSlice||Blob.prototype.mozSlice);e.blobSlice=t&&function(){return(this.slice||this.webkitSlice||this.mozSlice).apply(this,arguments)},e.metaDataParsers={jpeg:{65505:[]}},e.parseMetaData=function(t,i,a,o){a=a||{},o=o||{};var n=this,r=a.maxMetaDataSize||262144;!!("undefined"!=typeof DataView&&t&&t.size>=12&&"image/jpeg"===t.type&&e.blobSlice)&&e.readFile(e.blobSlice.call(t,0,r),function(t){if(t.target.error)return console.log(t.target.error),void i(o);var r,s,l,d,c=t.target.result,u=new DataView(c),f=2,g=u.byteLength-4,h=f;if(65496===u.getUint16(0)){for(;f<g&&((r=u.getUint16(f))>=65504&&r<=65519||65534===r);){if(s=u.getUint16(f+2)+2,f+s>u.byteLength){console.log("Invalid meta data: Invalid segment size.");break}if(l=e.metaDataParsers.jpeg[r])for(d=0;d<l.length;d+=1)l[d].call(n,u,f,s,o,a);h=f+=s}!a.disableImageHead&&h>6&&(c.slice?o.imageHead=c.slice(0,h):o.imageHead=new Uint8Array(c).subarray(0,h))}else console.log("Invalid JPEG file: Missing JPEG marker.");i(o)},"readAsArrayBuffer")||i(o)},e.hasMetaOption=function(e){return e&&e.meta};var i=e.transform;e.transform=function(t,a,o,n,r){e.hasMetaOption(a)?e.parseMetaData(n,function(r){i.call(e,t,a,o,n,r)},a,r):i.apply(e,arguments)}}),function(e){"use strict";"function"==typeof define&&define.amd?define(["./load-image","./load-image-meta"],e):"object"==typeof module&&module.exports?e(require("./load-image"),require("./load-image-meta")):e(window.loadImage)}(function(e){"use strict";"undefined"!=typeof fetch&&"undefined"!=typeof Request&&(e.fetchBlob=function(t,i,a){if(e.hasMetaOption(a))return fetch(new Request(t,a)).then(function(e){return e.blob()}).then(i).catch(function(e){console.log(e),i()});i()})}),function(e){"use strict";"function"==typeof define&&define.amd?define(["./load-image","./load-image-meta"],e):"object"==typeof module&&module.exports?e(require("./load-image"),require("./load-image-meta")):e(window.loadImage)}(function(e){"use strict";e.ExifMap=function(){return this},e.ExifMap.prototype.map={Orientation:274},e.ExifMap.prototype.get=function(e){return this[e]||this[this.map[e]]},e.getExifThumbnail=function(e,t,i){var a,o,n;{if(i&&!(t+i>e.byteLength)){for(a=[],o=0;o<i;o+=1)n=e.getUint8(t+o),a.push((n<16?"0":"")+n.toString(16));return"data:image/jpeg,%"+a.join("%")}console.log("Invalid Exif data: Invalid thumbnail data.")}},e.exifTagTypes={1:{getValue:function(e,t){return e.getUint8(t)},size:1},2:{getValue:function(e,t){return String.fromCharCode(e.getUint8(t))},size:1,ascii:!0},3:{getValue:function(e,t,i){return e.getUint16(t,i)},size:2},4:{getValue:function(e,t,i){return e.getUint32(t,i)},size:4},5:{getValue:function(e,t,i){return e.getUint32(t,i)/e.getUint32(t+4,i)},size:8},9:{getValue:function(e,t,i){return e.getInt32(t,i)},size:4},10:{getValue:function(e,t,i){return e.getInt32(t,i)/e.getInt32(t+4,i)},size:8}},e.exifTagTypes[7]=e.exifTagTypes[1],e.getExifValue=function(t,i,a,o,n,r){var s,l,d,c,u,f,g=e.exifTagTypes[o];if(g){if(s=g.size*n,!((l=s>4?i+t.getUint32(a+8,r):a+8)+s>t.byteLength)){if(1===n)return g.getValue(t,l,r);for(d=[],c=0;c<n;c+=1)d[c]=g.getValue(t,l+c*g.size,r);if(g.ascii){for(u="",c=0;c<d.length&&"\0"!==(f=d[c]);c+=1)u+=f;return u}return d}console.log("Invalid Exif data: Invalid data offset.")}else console.log("Invalid Exif data: Invalid tag type.")},e.parseExifTag=function(t,i,a,o,n){var r=t.getUint16(a,o);n.exif[r]=e.getExifValue(t,i,a,t.getUint16(a+2,o),t.getUint32(a+4,o),o)},e.parseExifTags=function(e,t,i,a,o){var n,r,s;if(i+6>e.byteLength)console.log("Invalid Exif data: Invalid directory offset.");else{if(n=e.getUint16(i,a),!((r=i+2+12*n)+4>e.byteLength)){for(s=0;s<n;s+=1)this.parseExifTag(e,t,i+2+12*s,a,o);return e.getUint32(r,a)}console.log("Invalid Exif data: Invalid directory size.")}},e.parseExifData=function(t,i,a,o,n){if(!n.disableExif){var r,s,l,d=i+10;if(1165519206===t.getUint32(i+4))if(d+8>t.byteLength)console.log("Invalid Exif data: Invalid segment size.");else if(0===t.getUint16(i+8)){switch(t.getUint16(d)){case 18761:r=!0;break;case 19789:r=!1;break;default:return void console.log("Invalid Exif data: Invalid byte alignment marker.")}42===t.getUint16(d+2,r)?(s=t.getUint32(d+4,r),o.exif=new e.ExifMap,(s=e.parseExifTags(t,d,d+s,r,o))&&!n.disableExifThumbnail&&(l={exif:{}},s=e.parseExifTags(t,d,d+s,r,l),l.exif[513]&&(o.exif.Thumbnail=e.getExifThumbnail(t,d+l.exif[513],l.exif[514]))),o.exif[34665]&&!n.disableExifSub&&e.parseExifTags(t,d,d+o.exif[34665],r,o),o.exif[34853]&&!n.disableExifGps&&e.parseExifTags(t,d,d+o.exif[34853],r,o)):console.log("Invalid Exif data: Missing TIFF marker.")}else console.log("Invalid Exif data: Missing byte alignment offset.")}},e.metaDataParsers.jpeg[65505].push(e.parseExifData)}),function(e){"use strict";"function"==typeof define&&define.amd?define(["./load-image","./load-image-exif"],e):"object"==typeof module&&module.exports?e(require("./load-image"),require("./load-image-exif")):e(window.loadImage)}(function(e){"use strict";e.ExifMap.prototype.tags={256:"ImageWidth",257:"ImageHeight",34665:"ExifIFDPointer",34853:"GPSInfoIFDPointer",40965:"InteroperabilityIFDPointer",258:"BitsPerSample",259:"Compression",262:"PhotometricInterpretation",274:"Orientation",277:"SamplesPerPixel",284:"PlanarConfiguration",530:"YCbCrSubSampling",531:"YCbCrPositioning",282:"XResolution",283:"YResolution",296:"ResolutionUnit",273:"StripOffsets",278:"RowsPerStrip",279:"StripByteCounts",513:"JPEGInterchangeFormat",514:"JPEGInterchangeFormatLength",301:"TransferFunction",318:"WhitePoint",319:"PrimaryChromaticities",529:"YCbCrCoefficients",532:"ReferenceBlackWhite",306:"DateTime",270:"ImageDescription",271:"Make",272:"Model",305:"Software",315:"Artist",33432:"Copyright",36864:"ExifVersion",40960:"FlashpixVersion",40961:"ColorSpace",40962:"PixelXDimension",40963:"PixelYDimension",42240:"Gamma",37121:"ComponentsConfiguration",37122:"CompressedBitsPerPixel",37500:"MakerNote",37510:"UserComment",40964:"RelatedSoundFile",36867:"DateTimeOriginal",36868:"DateTimeDigitized",37520:"SubSecTime",37521:"SubSecTimeOriginal",37522:"SubSecTimeDigitized",33434:"ExposureTime",33437:"FNumber",34850:"ExposureProgram",34852:"SpectralSensitivity",34855:"PhotographicSensitivity",34856:"OECF",34864:"SensitivityType",34865:"StandardOutputSensitivity",34866:"RecommendedExposureIndex",34867:"ISOSpeed",34868:"ISOSpeedLatitudeyyy",34869:"ISOSpeedLatitudezzz",37377:"ShutterSpeedValue",37378:"ApertureValue",37379:"BrightnessValue",37380:"ExposureBias",37381:"MaxApertureValue",37382:"SubjectDistance",37383:"MeteringMode",37384:"LightSource",37385:"Flash",37396:"SubjectArea",37386:"FocalLength",41483:"FlashEnergy",41484:"SpatialFrequencyResponse",41486:"FocalPlaneXResolution",41487:"FocalPlaneYResolution",41488:"FocalPlaneResolutionUnit",41492:"SubjectLocation",41493:"ExposureIndex",41495:"SensingMethod",41728:"FileSource",41729:"SceneType",41730:"CFAPattern",41985:"CustomRendered",41986:"ExposureMode",41987:"WhiteBalance",41988:"DigitalZoomRatio",41989:"FocalLengthIn35mmFilm",41990:"SceneCaptureType",41991:"GainControl",41992:"Contrast",41993:"Saturation",41994:"Sharpness",41995:"DeviceSettingDescription",41996:"SubjectDistanceRange",42016:"ImageUniqueID",42032:"CameraOwnerName",42033:"BodySerialNumber",42034:"LensSpecification",42035:"LensMake",42036:"LensModel",42037:"LensSerialNumber",0:"GPSVersionID",1:"GPSLatitudeRef",2:"GPSLatitude",3:"GPSLongitudeRef",4:"GPSLongitude",5:"GPSAltitudeRef",6:"GPSAltitude",7:"GPSTimeStamp",8:"GPSSatellites",9:"GPSStatus",10:"GPSMeasureMode",11:"GPSDOP",12:"GPSSpeedRef",13:"GPSSpeed",14:"GPSTrackRef",15:"GPSTrack",16:"GPSImgDirectionRef",17:"GPSImgDirection",18:"GPSMapDatum",19:"GPSDestLatitudeRef",20:"GPSDestLatitude",21:"GPSDestLongitudeRef",22:"GPSDestLongitude",23:"GPSDestBearingRef",24:"GPSDestBearing",25:"GPSDestDistanceRef",26:"GPSDestDistance",27:"GPSProcessingMethod",28:"GPSAreaInformation",29:"GPSDateStamp",30:"GPSDifferential",31:"GPSHPositioningError"},e.ExifMap.prototype.stringValues={ExposureProgram:{0:"Undefined",1:"Manual",2:"Normal program",3:"Aperture priority",4:"Shutter priority",5:"Creative program",6:"Action program",7:"Portrait mode",8:"Landscape mode"},MeteringMode:{0:"Unknown",1:"Average",2:"CenterWeightedAverage",3:"Spot",4:"MultiSpot",5:"Pattern",6:"Partial",255:"Other"},LightSource:{0:"Unknown",1:"Daylight",2:"Fluorescent",3:"Tungsten (incandescent light)",4:"Flash",9:"Fine weather",10:"Cloudy weather",11:"Shade",12:"Daylight fluorescent (D 5700 - 7100K)",13:"Day white fluorescent (N 4600 - 5400K)",14:"Cool white fluorescent (W 3900 - 4500K)",15:"White fluorescent (WW 3200 - 3700K)",17:"Standard light A",18:"Standard light B",19:"Standard light C",20:"D55",21:"D65",22:"D75",23:"D50",24:"ISO studio tungsten",255:"Other"},Flash:{0:"Flash did not fire",1:"Flash fired",5:"Strobe return light not detected",7:"Strobe return light detected",9:"Flash fired, compulsory flash mode",13:"Flash fired, compulsory flash mode, return light not detected",15:"Flash fired, compulsory flash mode, return light detected",16:"Flash did not fire, compulsory flash mode",24:"Flash did not fire, auto mode",25:"Flash fired, auto mode",29:"Flash fired, auto mode, return light not detected",31:"Flash fired, auto mode, return light detected",32:"No flash function",65:"Flash fired, red-eye reduction mode",69:"Flash fired, red-eye reduction mode, return light not detected",71:"Flash fired, red-eye reduction mode, return light detected",73:"Flash fired, compulsory flash mode, red-eye reduction mode",77:"Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected",79:"Flash fired, compulsory flash mode, red-eye reduction mode, return light detected",89:"Flash fired, auto mode, red-eye reduction mode",93:"Flash fired, auto mode, return light not detected, red-eye reduction mode",95:"Flash fired, auto mode, return light detected, red-eye reduction mode"},SensingMethod:{1:"Undefined",2:"One-chip color area sensor",3:"Two-chip color area sensor",4:"Three-chip color area sensor",5:"Color sequential area sensor",7:"Trilinear sensor",8:"Color sequential linear sensor"},SceneCaptureType:{0:"Standard",1:"Landscape",2:"Portrait",3:"Night scene"},SceneType:{1:"Directly photographed"},CustomRendered:{0:"Normal process",1:"Custom process"},WhiteBalance:{0:"Auto white balance",1:"Manual white balance"},GainControl:{0:"None",1:"Low gain up",2:"High gain up",3:"Low gain down",4:"High gain down"},Contrast:{0:"Normal",1:"Soft",2:"Hard"},Saturation:{0:"Normal",1:"Low saturation",2:"High saturation"},Sharpness:{0:"Normal",1:"Soft",2:"Hard"},SubjectDistanceRange:{0:"Unknown",1:"Macro",2:"Close view",3:"Distant view"},FileSource:{3:"DSC"},ComponentsConfiguration:{0:"",1:"Y",2:"Cb",3:"Cr",4:"R",5:"G",6:"B"},Orientation:{1:"top-left",2:"top-right",3:"bottom-right",4:"bottom-left",5:"left-top",6:"right-top",7:"right-bottom",8:"left-bottom"}},e.ExifMap.prototype.getText=function(e){var t=this.get(e);switch(e){case"LightSource":case"Flash":case"MeteringMode":case"ExposureProgram":case"SensingMethod":case"SceneCaptureType":case"SceneType":case"CustomRendered":case"WhiteBalance":case"GainControl":case"Contrast":case"Saturation":case"Sharpness":case"SubjectDistanceRange":case"FileSource":case"Orientation":return this.stringValues[e][t];case"ExifVersion":case"FlashpixVersion":if(!t)return;return String.fromCharCode(t[0],t[1],t[2],t[3]);case"ComponentsConfiguration":if(!t)return;return this.stringValues[e][t[0]]+this.stringValues[e][t[1]]+this.stringValues[e][t[2]]+this.stringValues[e][t[3]];case"GPSVersionID":if(!t)return;return t[0]+"."+t[1]+"."+t[2]+"."+t[3]}return String(t)},function(e){var t,i=e.tags,a=e.map;for(t in i)i.hasOwnProperty(t)&&(a[i[t]]=t)}(e.ExifMap.prototype),e.ExifMap.prototype.getAll=function(){var e,t,i={};for(e in this)this.hasOwnProperty(e)&&(t=this.tags[e])&&(i[t]=this.getText(t));return i}}),function(e){"use strict";"function"==typeof define&&define.amd?define(["./load-image","./load-image-scale","./load-image-meta"],e):"object"==typeof module&&module.exports?e(require("./load-image"),require("./load-image-scale"),require("./load-image-meta")):e(window.loadImage)}(function(e){"use strict";var t=e.hasCanvasOption,i=e.hasMetaOption,a=e.transformCoordinates,o=e.getTransformedOptions;e.hasCanvasOption=function(i){return!!i.orientation||t.call(e,i)},e.hasMetaOption=function(t){return t&&!0===t.orientation||i.call(e,t)},e.transformCoordinates=function(t,i){a.call(e,t,i);var o=t.getContext("2d"),n=t.width,r=t.height,s=t.style.width,l=t.style.height,d=i.orientation;if(d&&!(d>8))switch(d>4&&(t.width=r,t.height=n,t.style.width=l,t.style.height=s),d){case 2:o.translate(n,0),o.scale(-1,1);break;case 3:o.translate(n,r),o.rotate(Math.PI);break;case 4:o.translate(0,r),o.scale(1,-1);break;case 5:o.rotate(.5*Math.PI),o.scale(1,-1);break;case 6:o.rotate(.5*Math.PI),o.translate(0,-r);break;case 7:o.rotate(.5*Math.PI),o.translate(n,-r),o.scale(-1,1);break;case 8:o.rotate(-.5*Math.PI),o.translate(-n,0)}},e.getTransformedOptions=function(t,i,a){var n,r,s=o.call(e,t,i),l=s.orientation;if(!0===l&&a&&a.exif&&(l=a.exif.get("Orientation")),!l||l>8||1===l)return s;n={};for(r in s)s.hasOwnProperty(r)&&(n[r]=s[r]);switch(n.orientation=l,l){case 2:n.left=s.right,n.right=s.left;break;case 3:n.left=s.right,n.top=s.bottom,n.right=s.left,n.bottom=s.top;break;case 4:n.top=s.bottom,n.bottom=s.top;break;case 5:n.left=s.top,n.top=s.left,n.right=s.bottom,n.bottom=s.right;break;case 6:n.left=s.top,n.top=s.right,n.right=s.bottom,n.bottom=s.left;break;case 7:n.left=s.bottom,n.top=s.right,n.right=s.top,n.bottom=s.left;break;case 8:n.left=s.bottom,n.top=s.left,n.right=s.top,n.bottom=s.right}return n.orientation>4&&(n.maxWidth=s.maxHeight,n.maxHeight=s.maxWidth,n.minWidth=s.minHeight,n.minHeight=s.minWidth,n.sourceWidth=s.sourceHeight,n.sourceHeight=s.sourceWidth),n}});
1
+ !function(e){"use strict";function t(e,i,a){var o,n=document.createElement("img");return n.onerror=function(o){return t.onerror(n,o,e,i,a)},n.onload=function(o){return t.onload(n,o,e,i,a)},"string"==typeof e?(t.fetchBlob(e,function(i){i?(e=i,o=t.createObjectURL(e)):(o=e,a&&a.crossOrigin&&(n.crossOrigin=a.crossOrigin)),n.src=o},a),n):t.isInstanceOf("Blob",e)||t.isInstanceOf("File",e)?(o=n._objectURL=t.createObjectURL(e))?(n.src=o,n):t.readFile(e,function(e){var t=e.target;t&&t.result?n.src=t.result:i&&i(e)}):void 0}function i(e,i){!e._objectURL||i&&i.noRevoke||(t.revokeObjectURL(e._objectURL),delete e._objectURL)}var a=e.createObjectURL&&e||e.URL&&URL.revokeObjectURL&&URL||e.webkitURL&&webkitURL;t.fetchBlob=function(e,t,i){t()},t.isInstanceOf=function(e,t){return Object.prototype.toString.call(t)==="[object "+e+"]"},t.transform=function(e,t,i,a,o){i(e,o)},t.onerror=function(e,t,a,o,n){i(e,n),o&&o.call(e,t)},t.onload=function(e,a,o,n,r){i(e,r),n&&t.transform(e,r,n,o,{})},t.createObjectURL=function(e){return!!a&&a.createObjectURL(e)},t.revokeObjectURL=function(e){return!!a&&a.revokeObjectURL(e)},t.readFile=function(t,i,a){if(e.FileReader){var o=new FileReader;if(o.onload=o.onerror=i,a=a||"readAsDataURL",o[a])return o[a](t),o}return!1},"function"==typeof define&&define.amd?define(function(){return t}):"object"==typeof module&&module.exports?module.exports=t:e.loadImage=t}("undefined"!=typeof window&&window||this),function(e){"use strict";"function"==typeof define&&define.amd?define(["./load-image"],e):e("object"==typeof module&&module.exports?require("./load-image"):window.loadImage)}(function(e){"use strict";var t=e.transform;e.transform=function(i,a,o,n,r){t.call(e,e.scale(i,a,r),a,o,n,r)},e.transformCoordinates=function(){},e.getTransformedOptions=function(e,t){var i,a,o,n,r=t.aspectRatio;if(!r)return t;i={};for(a in t)t.hasOwnProperty(a)&&(i[a]=t[a]);return i.crop=!0,o=e.naturalWidth||e.width,n=e.naturalHeight||e.height,o/n>r?(i.maxWidth=n*r,i.maxHeight=n):(i.maxWidth=o,i.maxHeight=o/r),i},e.renderImageToCanvas=function(e,t,i,a,o,n,r,s,l,c){return e.getContext("2d").drawImage(t,i,a,o,n,r,s,l,c),e},e.hasCanvasOption=function(e){return e.canvas||e.crop||!!e.aspectRatio},e.scale=function(t,i,a){function o(){var e=Math.max((l||I)/I,(c||v)/v);e>1&&(I*=e,v*=e)}function n(){var e=Math.min((r||I)/I,(s||v)/v);e<1&&(I*=e,v*=e)}i=i||{};var r,s,l,c,d,u,f,g,p,m,h,S=document.createElement("canvas"),b=t.getContext||e.hasCanvasOption(i)&&S.getContext,y=t.naturalWidth||t.width,x=t.naturalHeight||t.height,I=y,v=x;if(b&&(f=(i=e.getTransformedOptions(t,i,a)).left||0,g=i.top||0,i.sourceWidth?(d=i.sourceWidth,void 0!==i.right&&void 0===i.left&&(f=y-d-i.right)):d=y-f-(i.right||0),i.sourceHeight?(u=i.sourceHeight,void 0!==i.bottom&&void 0===i.top&&(g=x-u-i.bottom)):u=x-g-(i.bottom||0),I=d,v=u),r=i.maxWidth,s=i.maxHeight,l=i.minWidth,c=i.minHeight,b&&r&&s&&i.crop?(I=r,v=s,(h=d/u-r/s)<0?(u=s*d/r,void 0===i.top&&void 0===i.bottom&&(g=(x-u)/2)):h>0&&(d=r*u/s,void 0===i.left&&void 0===i.right&&(f=(y-d)/2))):((i.contain||i.cover)&&(l=r=r||l,c=s=s||c),i.cover?(n(),o()):(o(),n())),b){if((p=i.pixelRatio)>1&&(S.style.width=I+"px",S.style.height=v+"px",I*=p,v*=p,S.getContext("2d").scale(p,p)),(m=i.downsamplingRatio)>0&&m<1&&I<d&&v<u)for(;d*m>I;)S.width=d*m,S.height=u*m,e.renderImageToCanvas(S,t,f,g,d,u,0,0,S.width,S.height),f=0,g=0,d=S.width,u=S.height,(t=document.createElement("canvas")).width=d,t.height=u,e.renderImageToCanvas(t,S,0,0,d,u,0,0,d,u);return S.width=I,S.height=v,e.transformCoordinates(S,i),e.renderImageToCanvas(S,t,f,g,d,u,0,0,I,v)}return t.width=I,t.height=v,t}}),function(e){"use strict";"function"==typeof define&&define.amd?define(["./load-image"],e):e("object"==typeof module&&module.exports?require("./load-image"):window.loadImage)}(function(e){"use strict";var t="undefined"!=typeof Blob&&(Blob.prototype.slice||Blob.prototype.webkitSlice||Blob.prototype.mozSlice);e.blobSlice=t&&function(){return(this.slice||this.webkitSlice||this.mozSlice).apply(this,arguments)},e.metaDataParsers={jpeg:{65505:[],65517:[]}},e.parseMetaData=function(t,i,a,o){a=a||{},o=o||{};var n=this,r=a.maxMetaDataSize||262144;!!("undefined"!=typeof DataView&&t&&t.size>=12&&"image/jpeg"===t.type&&e.blobSlice)&&e.readFile(e.blobSlice.call(t,0,r),function(t){if(t.target.error)return console.log(t.target.error),void i(o);var r,s,l,c,d=t.target.result,u=new DataView(d),f=2,g=u.byteLength-4,p=f;if(65496===u.getUint16(0)){for(;f<g&&((r=u.getUint16(f))>=65504&&r<=65519||65534===r);){if(s=u.getUint16(f+2)+2,f+s>u.byteLength){console.log("Invalid meta data: Invalid segment size.");break}if(l=e.metaDataParsers.jpeg[r])for(c=0;c<l.length;c+=1)l[c].call(n,u,f,s,o,a);p=f+=s}!a.disableImageHead&&p>6&&(d.slice?o.imageHead=d.slice(0,p):o.imageHead=new Uint8Array(d).subarray(0,p))}else console.log("Invalid JPEG file: Missing JPEG marker.");i(o)},"readAsArrayBuffer")||i(o)},e.hasMetaOption=function(e){return e&&e.meta};var i=e.transform;e.transform=function(t,a,o,n,r){e.hasMetaOption(a)?e.parseMetaData(n,function(r){i.call(e,t,a,o,n,r)},a,r):i.apply(e,arguments)}}),function(e){"use strict";"function"==typeof define&&define.amd?define(["./load-image","./load-image-meta"],e):"object"==typeof module&&module.exports?e(require("./load-image"),require("./load-image-meta")):e(window.loadImage)}(function(e){"use strict";"undefined"!=typeof fetch&&"undefined"!=typeof Request&&(e.fetchBlob=function(t,i,a){if(e.hasMetaOption(a))return fetch(new Request(t,a)).then(function(e){return e.blob()}).then(i).catch(function(e){console.log(e),i()});i()})}),function(e){"use strict";"function"==typeof define&&define.amd?define(["./load-image","./load-image-scale","./load-image-meta"],e):"object"==typeof module&&module.exports?e(require("./load-image"),require("./load-image-scale"),require("./load-image-meta")):e(window.loadImage)}(function(e){"use strict";var t=e.hasCanvasOption,i=e.hasMetaOption,a=e.transformCoordinates,o=e.getTransformedOptions;e.hasCanvasOption=function(i){return!!i.orientation||t.call(e,i)},e.hasMetaOption=function(t){return t&&!0===t.orientation||i.call(e,t)},e.transformCoordinates=function(t,i){a.call(e,t,i);var o=t.getContext("2d"),n=t.width,r=t.height,s=t.style.width,l=t.style.height,c=i.orientation;if(c&&!(c>8))switch(c>4&&(t.width=r,t.height=n,t.style.width=l,t.style.height=s),c){case 2:o.translate(n,0),o.scale(-1,1);break;case 3:o.translate(n,r),o.rotate(Math.PI);break;case 4:o.translate(0,r),o.scale(1,-1);break;case 5:o.rotate(.5*Math.PI),o.scale(1,-1);break;case 6:o.rotate(.5*Math.PI),o.translate(0,-r);break;case 7:o.rotate(.5*Math.PI),o.translate(n,-r),o.scale(-1,1);break;case 8:o.rotate(-.5*Math.PI),o.translate(-n,0)}},e.getTransformedOptions=function(t,i,a){var n,r,s=o.call(e,t,i),l=s.orientation;if(!0===l&&a&&a.exif&&(l=a.exif.get("Orientation")),!l||l>8||1===l)return s;n={};for(r in s)s.hasOwnProperty(r)&&(n[r]=s[r]);switch(n.orientation=l,l){case 2:n.left=s.right,n.right=s.left;break;case 3:n.left=s.right,n.top=s.bottom,n.right=s.left,n.bottom=s.top;break;case 4:n.top=s.bottom,n.bottom=s.top;break;case 5:n.left=s.top,n.top=s.left,n.right=s.bottom,n.bottom=s.right;break;case 6:n.left=s.top,n.top=s.right,n.right=s.bottom,n.bottom=s.left;break;case 7:n.left=s.bottom,n.top=s.right,n.right=s.top,n.bottom=s.left;break;case 8:n.left=s.bottom,n.top=s.left,n.right=s.top,n.bottom=s.right}return n.orientation>4&&(n.maxWidth=s.maxHeight,n.maxHeight=s.maxWidth,n.minWidth=s.minHeight,n.minHeight=s.minWidth,n.sourceWidth=s.sourceHeight,n.sourceHeight=s.sourceWidth),n}}),function(e){"use strict";"function"==typeof define&&define.amd?define(["./load-image","./load-image-meta"],e):"object"==typeof module&&module.exports?e(require("./load-image"),require("./load-image-meta")):e(window.loadImage)}(function(e){"use strict";e.ExifMap=function(){return this},e.ExifMap.prototype.map={Orientation:274},e.ExifMap.prototype.get=function(e){return this[e]||this[this.map[e]]},e.getExifThumbnail=function(t,i,a){if(a&&!(i+a>t.byteLength))return e.createObjectURL(new Blob([t.buffer.slice(i,i+a)]));console.log("Invalid Exif data: Invalid thumbnail data.")},e.exifTagTypes={1:{getValue:function(e,t){return e.getUint8(t)},size:1},2:{getValue:function(e,t){return String.fromCharCode(e.getUint8(t))},size:1,ascii:!0},3:{getValue:function(e,t,i){return e.getUint16(t,i)},size:2},4:{getValue:function(e,t,i){return e.getUint32(t,i)},size:4},5:{getValue:function(e,t,i){return e.getUint32(t,i)/e.getUint32(t+4,i)},size:8},9:{getValue:function(e,t,i){return e.getInt32(t,i)},size:4},10:{getValue:function(e,t,i){return e.getInt32(t,i)/e.getInt32(t+4,i)},size:8}},e.exifTagTypes[7]=e.exifTagTypes[1],e.getExifValue=function(t,i,a,o,n,r){var s,l,c,d,u,f,g=e.exifTagTypes[o];if(g){if(s=g.size*n,!((l=s>4?i+t.getUint32(a+8,r):a+8)+s>t.byteLength)){if(1===n)return g.getValue(t,l,r);for(c=[],d=0;d<n;d+=1)c[d]=g.getValue(t,l+d*g.size,r);if(g.ascii){for(u="",d=0;d<c.length&&"\0"!==(f=c[d]);d+=1)u+=f;return u}return c}console.log("Invalid Exif data: Invalid data offset.")}else console.log("Invalid Exif data: Invalid tag type.")},e.parseExifTag=function(t,i,a,o,n){var r=t.getUint16(a,o);n.exif[r]=e.getExifValue(t,i,a,t.getUint16(a+2,o),t.getUint32(a+4,o),o)},e.parseExifTags=function(e,t,i,a,o){var n,r,s;if(i+6>e.byteLength)console.log("Invalid Exif data: Invalid directory offset.");else{if(n=e.getUint16(i,a),!((r=i+2+12*n)+4>e.byteLength)){for(s=0;s<n;s+=1)this.parseExifTag(e,t,i+2+12*s,a,o);return e.getUint32(r,a)}console.log("Invalid Exif data: Invalid directory size.")}},e.parseExifData=function(t,i,a,o,n){if(!n.disableExif){var r,s,l,c=i+10;if(1165519206===t.getUint32(i+4))if(c+8>t.byteLength)console.log("Invalid Exif data: Invalid segment size.");else if(0===t.getUint16(i+8)){switch(t.getUint16(c)){case 18761:r=!0;break;case 19789:r=!1;break;default:return void console.log("Invalid Exif data: Invalid byte alignment marker.")}42===t.getUint16(c+2,r)?(s=t.getUint32(c+4,r),o.exif=new e.ExifMap,(s=e.parseExifTags(t,c,c+s,r,o))&&!n.disableExifThumbnail&&(l={exif:{}},s=e.parseExifTags(t,c,c+s,r,l),l.exif[513]&&(o.exif.Thumbnail=e.getExifThumbnail(t,c+l.exif[513],l.exif[514]))),o.exif[34665]&&!n.disableExifSub&&e.parseExifTags(t,c,c+o.exif[34665],r,o),o.exif[34853]&&!n.disableExifGps&&e.parseExifTags(t,c,c+o.exif[34853],r,o)):console.log("Invalid Exif data: Missing TIFF marker.")}else console.log("Invalid Exif data: Missing byte alignment offset.")}},e.metaDataParsers.jpeg[65505].push(e.parseExifData)}),function(e){"use strict";"function"==typeof define&&define.amd?define(["./load-image","./load-image-exif"],e):"object"==typeof module&&module.exports?e(require("./load-image"),require("./load-image-exif")):e(window.loadImage)}(function(e){"use strict";e.ExifMap.prototype.tags={256:"ImageWidth",257:"ImageHeight",34665:"ExifIFDPointer",34853:"GPSInfoIFDPointer",40965:"InteroperabilityIFDPointer",258:"BitsPerSample",259:"Compression",262:"PhotometricInterpretation",274:"Orientation",277:"SamplesPerPixel",284:"PlanarConfiguration",530:"YCbCrSubSampling",531:"YCbCrPositioning",282:"XResolution",283:"YResolution",296:"ResolutionUnit",273:"StripOffsets",278:"RowsPerStrip",279:"StripByteCounts",513:"JPEGInterchangeFormat",514:"JPEGInterchangeFormatLength",301:"TransferFunction",318:"WhitePoint",319:"PrimaryChromaticities",529:"YCbCrCoefficients",532:"ReferenceBlackWhite",306:"DateTime",270:"ImageDescription",271:"Make",272:"Model",305:"Software",315:"Artist",33432:"Copyright",36864:"ExifVersion",40960:"FlashpixVersion",40961:"ColorSpace",40962:"PixelXDimension",40963:"PixelYDimension",42240:"Gamma",37121:"ComponentsConfiguration",37122:"CompressedBitsPerPixel",37500:"MakerNote",37510:"UserComment",40964:"RelatedSoundFile",36867:"DateTimeOriginal",36868:"DateTimeDigitized",37520:"SubSecTime",37521:"SubSecTimeOriginal",37522:"SubSecTimeDigitized",33434:"ExposureTime",33437:"FNumber",34850:"ExposureProgram",34852:"SpectralSensitivity",34855:"PhotographicSensitivity",34856:"OECF",34864:"SensitivityType",34865:"StandardOutputSensitivity",34866:"RecommendedExposureIndex",34867:"ISOSpeed",34868:"ISOSpeedLatitudeyyy",34869:"ISOSpeedLatitudezzz",37377:"ShutterSpeedValue",37378:"ApertureValue",37379:"BrightnessValue",37380:"ExposureBias",37381:"MaxApertureValue",37382:"SubjectDistance",37383:"MeteringMode",37384:"LightSource",37385:"Flash",37396:"SubjectArea",37386:"FocalLength",41483:"FlashEnergy",41484:"SpatialFrequencyResponse",41486:"FocalPlaneXResolution",41487:"FocalPlaneYResolution",41488:"FocalPlaneResolutionUnit",41492:"SubjectLocation",41493:"ExposureIndex",41495:"SensingMethod",41728:"FileSource",41729:"SceneType",41730:"CFAPattern",41985:"CustomRendered",41986:"ExposureMode",41987:"WhiteBalance",41988:"DigitalZoomRatio",41989:"FocalLengthIn35mmFilm",41990:"SceneCaptureType",41991:"GainControl",41992:"Contrast",41993:"Saturation",41994:"Sharpness",41995:"DeviceSettingDescription",41996:"SubjectDistanceRange",42016:"ImageUniqueID",42032:"CameraOwnerName",42033:"BodySerialNumber",42034:"LensSpecification",42035:"LensMake",42036:"LensModel",42037:"LensSerialNumber",0:"GPSVersionID",1:"GPSLatitudeRef",2:"GPSLatitude",3:"GPSLongitudeRef",4:"GPSLongitude",5:"GPSAltitudeRef",6:"GPSAltitude",7:"GPSTimeStamp",8:"GPSSatellites",9:"GPSStatus",10:"GPSMeasureMode",11:"GPSDOP",12:"GPSSpeedRef",13:"GPSSpeed",14:"GPSTrackRef",15:"GPSTrack",16:"GPSImgDirectionRef",17:"GPSImgDirection",18:"GPSMapDatum",19:"GPSDestLatitudeRef",20:"GPSDestLatitude",21:"GPSDestLongitudeRef",22:"GPSDestLongitude",23:"GPSDestBearingRef",24:"GPSDestBearing",25:"GPSDestDistanceRef",26:"GPSDestDistance",27:"GPSProcessingMethod",28:"GPSAreaInformation",29:"GPSDateStamp",30:"GPSDifferential",31:"GPSHPositioningError"},e.ExifMap.prototype.stringValues={ExposureProgram:{0:"Undefined",1:"Manual",2:"Normal program",3:"Aperture priority",4:"Shutter priority",5:"Creative program",6:"Action program",7:"Portrait mode",8:"Landscape mode"},MeteringMode:{0:"Unknown",1:"Average",2:"CenterWeightedAverage",3:"Spot",4:"MultiSpot",5:"Pattern",6:"Partial",255:"Other"},LightSource:{0:"Unknown",1:"Daylight",2:"Fluorescent",3:"Tungsten (incandescent light)",4:"Flash",9:"Fine weather",10:"Cloudy weather",11:"Shade",12:"Daylight fluorescent (D 5700 - 7100K)",13:"Day white fluorescent (N 4600 - 5400K)",14:"Cool white fluorescent (W 3900 - 4500K)",15:"White fluorescent (WW 3200 - 3700K)",17:"Standard light A",18:"Standard light B",19:"Standard light C",20:"D55",21:"D65",22:"D75",23:"D50",24:"ISO studio tungsten",255:"Other"},Flash:{0:"Flash did not fire",1:"Flash fired",5:"Strobe return light not detected",7:"Strobe return light detected",9:"Flash fired, compulsory flash mode",13:"Flash fired, compulsory flash mode, return light not detected",15:"Flash fired, compulsory flash mode, return light detected",16:"Flash did not fire, compulsory flash mode",24:"Flash did not fire, auto mode",25:"Flash fired, auto mode",29:"Flash fired, auto mode, return light not detected",31:"Flash fired, auto mode, return light detected",32:"No flash function",65:"Flash fired, red-eye reduction mode",69:"Flash fired, red-eye reduction mode, return light not detected",71:"Flash fired, red-eye reduction mode, return light detected",73:"Flash fired, compulsory flash mode, red-eye reduction mode",77:"Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected",79:"Flash fired, compulsory flash mode, red-eye reduction mode, return light detected",89:"Flash fired, auto mode, red-eye reduction mode",93:"Flash fired, auto mode, return light not detected, red-eye reduction mode",95:"Flash fired, auto mode, return light detected, red-eye reduction mode"},SensingMethod:{1:"Undefined",2:"One-chip color area sensor",3:"Two-chip color area sensor",4:"Three-chip color area sensor",5:"Color sequential area sensor",7:"Trilinear sensor",8:"Color sequential linear sensor"},SceneCaptureType:{0:"Standard",1:"Landscape",2:"Portrait",3:"Night scene"},SceneType:{1:"Directly photographed"},CustomRendered:{0:"Normal process",1:"Custom process"},WhiteBalance:{0:"Auto white balance",1:"Manual white balance"},GainControl:{0:"None",1:"Low gain up",2:"High gain up",3:"Low gain down",4:"High gain down"},Contrast:{0:"Normal",1:"Soft",2:"Hard"},Saturation:{0:"Normal",1:"Low saturation",2:"High saturation"},Sharpness:{0:"Normal",1:"Soft",2:"Hard"},SubjectDistanceRange:{0:"Unknown",1:"Macro",2:"Close view",3:"Distant view"},FileSource:{3:"DSC"},ComponentsConfiguration:{0:"",1:"Y",2:"Cb",3:"Cr",4:"R",5:"G",6:"B"},Orientation:{1:"top-left",2:"top-right",3:"bottom-right",4:"bottom-left",5:"left-top",6:"right-top",7:"right-bottom",8:"left-bottom"}},e.ExifMap.prototype.getText=function(e){var t=this.get(e);switch(e){case"LightSource":case"Flash":case"MeteringMode":case"ExposureProgram":case"SensingMethod":case"SceneCaptureType":case"SceneType":case"CustomRendered":case"WhiteBalance":case"GainControl":case"Contrast":case"Saturation":case"Sharpness":case"SubjectDistanceRange":case"FileSource":case"Orientation":return this.stringValues[e][t];case"ExifVersion":case"FlashpixVersion":if(!t)return;return String.fromCharCode(t[0],t[1],t[2],t[3]);case"ComponentsConfiguration":if(!t)return;return this.stringValues[e][t[0]]+this.stringValues[e][t[1]]+this.stringValues[e][t[2]]+this.stringValues[e][t[3]];case"GPSVersionID":if(!t)return;return t[0]+"."+t[1]+"."+t[2]+"."+t[3]}return String(t)},function(e){var t,i=e.tags,a=e.map;for(t in i)i.hasOwnProperty(t)&&(a[i[t]]=t)}(e.ExifMap.prototype),e.ExifMap.prototype.getAll=function(){var e,t,i={};for(e in this)this.hasOwnProperty(e)&&(t=this.tags[e])&&(i[t]=this.getText(t));return i}}),function(e){"use strict";"function"==typeof define&&define.amd?define(["./load-image","./load-image-meta"],e):"object"==typeof module&&module.exports?e(require("./load-image"),require("./load-image-meta")):e(window.loadImage)}(function(e){"use strict";e.IptcMap=function(){return this},e.IptcMap.prototype.map={ObjectName:5},e.IptcMap.prototype.get=function(e){return this[e]||this[this.map[e]]},e.parseIptcTags=function(e,t,i,a){for(var o,n,r=t;r<t+i;)28===e.getUint8(r)&&2===e.getUint8(r+1)&&(n=e.getUint8(r+2))in a.iptc.tags&&(o=function(e,t,i){for(var a="",o=t;o<t+i;o++)a+=String.fromCharCode(e.getUint8(o));return a}(e,r+5,e.getInt16(r+3)),a.iptc.hasOwnProperty(n)?a.iptc[n]instanceof Array?a.iptc[n].push(o):a.iptc[n]=[a.iptc[n],o]:a.iptc[n]=o),r++},e.parseIptcData=function(t,i,a,o,n){if(!n.disableIptc){for(var r=i+a;i+8<r;){if(function(e,t){return 943868237===e.getUint32(t)&&1028===e.getUint16(t+4)}(t,i)){var s=t.getUint8(i+7);s%2!=0&&(s+=1),0===s&&(s=4);var l=i+8+s;if(l>r){console.log("Invalid IPTC data: Invalid segment offset.");break}var c=t.getUint16(i+6+s);if(i+c>r){console.log("Invalid IPTC data: Invalid segment size.");break}return o.iptc=new e.IptcMap,e.parseIptcTags(t,l,c,o)}i++}console.log("No IPTC data at this offset - could be XMP")}},e.metaDataParsers.jpeg[65517].push(e.parseIptcData)}),function(e){"use strict";"function"==typeof define&&define.amd?define(["./load-image","./load-image-iptc"],e):"object"==typeof module&&module.exports?e(require("./load-image"),require("./load-image-iptc")):e(window.loadImage)}(function(e){"use strict";e.IptcMap.prototype.tags={3:"ObjectType",4:"ObjectAttribute",5:"ObjectName",7:"EditStatus",8:"EditorialUpdate",10:"Urgency",12:"SubjectRef",15:"Category",20:"SupplCategory",22:"FixtureID",25:"Keywords",26:"ContentLocCode",27:"ContentLocName",30:"ReleaseDate",35:"ReleaseTime",37:"ExpirationDate",38:"ExpirationTime",40:"SpecialInstructions",42:"ActionAdvised",45:"RefService",47:"RefDate",50:"RefNumber",55:"DateCreated",60:"TimeCreated",62:"DigitalCreationDate",63:"DigitalCreationTime",65:"OriginatingProgram",70:"ProgramVersion",75:"ObjectCycle",80:"Byline",85:"BylineTitle",90:"City",92:"Sublocation",95:"State",100:"CountryCode",101:"CountryName",103:"OrigTransRef",105:"Headline",110:"Credit",115:"Source",116:"CopyrightNotice",118:"Contact",120:"Caption",122:"WriterEditor",130:"ImageType",131:"ImageOrientation",135:"LanguageID"},e.IptcMap.prototype.getText=function(e){var t=this.get(e);return String(t)},function(e){var t,i=e.tags,a=e.map||{};for(t in i)i.hasOwnProperty(t)&&(a[i[t]]=t)}(e.IptcMap.prototype),e.IptcMap.prototype.getAll=function(){var e,t,i={};for(e in this)this.hasOwnProperty(e)&&(t=this.tags[e])&&(i[t]=this.getText(t));return i}});
2
2
  //# sourceMappingURL=load-image.all.min.js.map
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cloudinary
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.1
4
+ version: 1.20.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nadav Soferman
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2018-03-05 00:00:00.000000000 Z
13
+ date: 2021-03-26 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: aws_cf_signer
@@ -27,21 +27,21 @@ dependencies:
27
27
  - !ruby/object:Gem::Version
28
28
  version: '0'
29
29
  - !ruby/object:Gem::Dependency
30
- name: rspec
30
+ name: rest-client
31
31
  requirement: !ruby/object:Gem::Requirement
32
32
  requirements:
33
33
  - - ">="
34
34
  - !ruby/object:Gem::Version
35
- version: '3.5'
36
- type: :development
35
+ version: 2.0.0
36
+ type: :runtime
37
37
  prerelease: false
38
38
  version_requirements: !ruby/object:Gem::Requirement
39
39
  requirements:
40
40
  - - ">="
41
41
  - !ruby/object:Gem::Version
42
- version: '3.5'
42
+ version: 2.0.0
43
43
  - !ruby/object:Gem::Dependency
44
- name: rspec-rails
44
+ name: actionpack
45
45
  requirement: !ruby/object:Gem::Requirement
46
46
  requirements:
47
47
  - - ">="
@@ -55,7 +55,7 @@ dependencies:
55
55
  - !ruby/object:Gem::Version
56
56
  version: '0'
57
57
  - !ruby/object:Gem::Dependency
58
- name: rake
58
+ name: nokogiri
59
59
  requirement: !ruby/object:Gem::Requirement
60
60
  requirements:
61
61
  - - ">="
@@ -69,13 +69,27 @@ dependencies:
69
69
  - !ruby/object:Gem::Version
70
70
  version: '0'
71
71
  - !ruby/object:Gem::Dependency
72
- name: rest-client
72
+ name: rake
73
+ requirement: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: 13.0.1
78
+ type: :development
79
+ prerelease: false
80
+ version_requirements: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: 13.0.1
85
+ - !ruby/object:Gem::Dependency
86
+ name: sqlite3
73
87
  requirement: !ruby/object:Gem::Requirement
74
88
  requirements:
75
89
  - - ">="
76
90
  - !ruby/object:Gem::Version
77
91
  version: '0'
78
- type: :runtime
92
+ type: :development
79
93
  prerelease: false
80
94
  version_requirements: !ruby/object:Gem::Requirement
81
95
  requirements:
@@ -83,7 +97,21 @@ dependencies:
83
97
  - !ruby/object:Gem::Version
84
98
  version: '0'
85
99
  - !ruby/object:Gem::Dependency
86
- name: actionpack
100
+ name: rspec
101
+ requirement: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '3.5'
106
+ type: :development
107
+ prerelease: false
108
+ version_requirements: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '3.5'
113
+ - !ruby/object:Gem::Dependency
114
+ name: rspec-retry
87
115
  requirement: !ruby/object:Gem::Requirement
88
116
  requirements:
89
117
  - - ">="
@@ -97,7 +125,21 @@ dependencies:
97
125
  - !ruby/object:Gem::Version
98
126
  version: '0'
99
127
  - !ruby/object:Gem::Dependency
100
- name: simplecov
128
+ name: rails
129
+ requirement: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - "~>"
132
+ - !ruby/object:Gem::Version
133
+ version: '5.2'
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - "~>"
139
+ - !ruby/object:Gem::Version
140
+ version: '5.2'
141
+ - !ruby/object:Gem::Dependency
142
+ name: rspec-rails
101
143
  requirement: !ruby/object:Gem::Requirement
102
144
  requirements:
103
145
  - - ">="
@@ -124,6 +166,20 @@ dependencies:
124
166
  - - ">="
125
167
  - !ruby/object:Gem::Version
126
168
  version: '0'
169
+ - !ruby/object:Gem::Dependency
170
+ name: simplecov
171
+ requirement: !ruby/object:Gem::Requirement
172
+ requirements:
173
+ - - ">"
174
+ - !ruby/object:Gem::Version
175
+ version: 0.18.0
176
+ type: :development
177
+ prerelease: false
178
+ version_requirements: !ruby/object:Gem::Requirement
179
+ requirements:
180
+ - - ">"
181
+ - !ruby/object:Gem::Version
182
+ version: 0.18.0
127
183
  description: Client library for easily using the Cloudinary service
128
184
  email:
129
185
  - nadav.soferman@cloudinary.com
@@ -133,6 +189,9 @@ executables: []
133
189
  extensions: []
134
190
  extra_rdoc_files: []
135
191
  files:
192
+ - ".github/ISSUE_TEMPLATE/bug_report.md"
193
+ - ".github/ISSUE_TEMPLATE/feature_request.md"
194
+ - ".github/pull_request_template.md"
136
195
  - ".gitignore"
137
196
  - ".rspec"
138
197
  - ".travis.yml"
@@ -142,17 +201,29 @@ files:
142
201
  - README.md
143
202
  - Rakefile
144
203
  - cloudinary.gemspec
204
+ - lib/active_storage/blob_key.rb
205
+ - lib/active_storage/service/cloudinary_service.rb
145
206
  - lib/cloudinary.rb
207
+ - lib/cloudinary/account_api.rb
208
+ - lib/cloudinary/account_config.rb
146
209
  - lib/cloudinary/api.rb
147
210
  - lib/cloudinary/auth_token.rb
211
+ - lib/cloudinary/base_api.rb
212
+ - lib/cloudinary/base_config.rb
148
213
  - lib/cloudinary/blob.rb
214
+ - lib/cloudinary/cache.rb
215
+ - lib/cloudinary/cache/breakpoints_cache.rb
216
+ - lib/cloudinary/cache/key_value_cache_adapter.rb
217
+ - lib/cloudinary/cache/rails_cache_adapter.rb
218
+ - lib/cloudinary/cache/storage/rails_cache_storage.rb
149
219
  - lib/cloudinary/carrier_wave.rb
150
220
  - lib/cloudinary/carrier_wave/error.rb
151
221
  - lib/cloudinary/carrier_wave/preloaded.rb
152
222
  - lib/cloudinary/carrier_wave/process.rb
153
223
  - lib/cloudinary/carrier_wave/remote.rb
154
224
  - lib/cloudinary/carrier_wave/storage.rb
155
- - lib/cloudinary/controller.rb
225
+ - lib/cloudinary/cloudinary_controller.rb
226
+ - lib/cloudinary/config.rb
156
227
  - lib/cloudinary/downloader.rb
157
228
  - lib/cloudinary/engine.rb
158
229
  - lib/cloudinary/exceptions.rb
@@ -162,38 +233,18 @@ files:
162
233
  - lib/cloudinary/ostruct2.rb
163
234
  - lib/cloudinary/preloaded_file.rb
164
235
  - lib/cloudinary/railtie.rb
236
+ - lib/cloudinary/responsive.rb
165
237
  - lib/cloudinary/search.rb
166
238
  - lib/cloudinary/static.rb
167
239
  - lib/cloudinary/uploader.rb
168
240
  - lib/cloudinary/utils.rb
169
241
  - lib/cloudinary/version.rb
170
242
  - lib/cloudinary/video_helper.rb
171
- - lib/tasks/cloudinary.rake
172
- - spec/access_control_spec.rb
173
- - spec/api_spec.rb
174
- - spec/archive_spec.rb
175
- - spec/auth_token_spec.rb
176
- - spec/cloudinary_helper_spec.rb
177
- - spec/cloudinary_spec.rb
178
- - spec/data/sync_static/app/assets/javascripts/1.coffee
179
- - spec/data/sync_static/app/assets/javascripts/1.js
180
- - spec/data/sync_static/app/assets/stylesheets/1.css
181
- - spec/docx.docx
182
- - spec/favicon.ico
183
- - spec/logo.png
184
- - spec/rake_spec.rb
185
- - spec/sample_asset_file.tsv
186
- - spec/search_spec.rb
187
- - spec/spec_helper.rb
188
- - spec/storage_spec.rb
189
- - spec/streaminig_profiles_api_spec.rb
190
- - spec/support/helpers/temp_file_helpers.rb
191
- - spec/support/shared_contexts/rake.rb
192
- - spec/uploader_spec.rb
193
- - spec/utils_methods_spec.rb
194
- - spec/utils_spec.rb
195
- - spec/video_tag_spec.rb
196
- - spec/video_url_spec.rb
243
+ - lib/tasks/cloudinary/fetch_assets.rake
244
+ - lib/tasks/cloudinary/sync_static.rake
245
+ - tools/allocate_test_cloud.sh
246
+ - tools/get_test_cloud.sh
247
+ - tools/update_version
197
248
  - vendor/assets/html/cloudinary_cors.html
198
249
  - vendor/assets/javascripts/cloudinary/canvas-to-blob.min.js
199
250
  - vendor/assets/javascripts/cloudinary/index.js
@@ -225,34 +276,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
225
276
  - !ruby/object:Gem::Version
226
277
  version: '0'
227
278
  requirements: []
228
- rubyforge_project: cloudinary
229
- rubygems_version: 2.6.12
279
+ rubygems_version: 3.1.2
230
280
  signing_key:
231
281
  specification_version: 4
232
282
  summary: Client library for easily using the Cloudinary service
233
- test_files:
234
- - spec/access_control_spec.rb
235
- - spec/api_spec.rb
236
- - spec/archive_spec.rb
237
- - spec/auth_token_spec.rb
238
- - spec/cloudinary_helper_spec.rb
239
- - spec/cloudinary_spec.rb
240
- - spec/data/sync_static/app/assets/javascripts/1.coffee
241
- - spec/data/sync_static/app/assets/javascripts/1.js
242
- - spec/data/sync_static/app/assets/stylesheets/1.css
243
- - spec/docx.docx
244
- - spec/favicon.ico
245
- - spec/logo.png
246
- - spec/rake_spec.rb
247
- - spec/sample_asset_file.tsv
248
- - spec/search_spec.rb
249
- - spec/spec_helper.rb
250
- - spec/storage_spec.rb
251
- - spec/streaminig_profiles_api_spec.rb
252
- - spec/support/helpers/temp_file_helpers.rb
253
- - spec/support/shared_contexts/rake.rb
254
- - spec/uploader_spec.rb
255
- - spec/utils_methods_spec.rb
256
- - spec/utils_spec.rb
257
- - spec/video_tag_spec.rb
258
- - spec/video_url_spec.rb
283
+ test_files: []
@@ -1,99 +0,0 @@
1
- require 'rspec'
2
- require 'cloudinary'
3
- require 'spec_helper'
4
- require 'time'
5
-
6
- # Calculates days as seconds
7
- def days(n)
8
- n * 3600 * 24
9
- end
10
-
11
- describe "Access Control" do
12
- let (:acl) {{
13
- :access_type => 'anonymous',
14
- :start => '2019-02-22 16:20:57 +0200',
15
- :end => '2019-03-22 00:00 +0200'
16
- }}
17
- let (:acl_2) {{
18
- :access_type => 'anonymous',
19
- :start => '2019-02-22 16:20:57Z',
20
- :end => '2019-03-22 00:00 +0200'
21
- }}
22
- let (:acl_string) {
23
- '{"access_type":"anonymous","start":"2019-02-22 16:20:57 +0200","end":"2019-03-22 00:00 +0200"}'
24
- }
25
- let (:options) {{
26
- :public_id => TIMESTAMP_TAG,
27
- :tags => [TEST_TAG, TIMESTAMP_TAG, 'access_control_test']
28
- }}
29
- let(:resource ){
30
- Cloudinary::Uploader.upload(
31
- TEST_IMG,
32
- options)
33
- }
34
- describe 'build_upload_params' do
35
- it "should accept a Hash value" do
36
- params = Cloudinary::Uploader.build_upload_params access_control: acl
37
- expect(params).to have_key(:access_control)
38
- expect(params[:access_control]).to be_a String
39
- expect(params[:access_control]).to match(/^\[.+\]$/)
40
-
41
- end
42
- it "should accept an array of Hash values" do
43
- params = Cloudinary::Uploader.build_upload_params access_control: [acl, acl_2]
44
- expect(params).to have_key(:access_control)
45
- expect(params[:access_control]).to be_a String
46
- expect(params[:access_control]).to match(/^\[.+\]$/)
47
- j = JSON.parse(params[:access_control])
48
- expect(j.length).to be(2)
49
- expect(j[0]["access_type"]).to eql(acl[:access_type])
50
- expect(j[0]["start"]).to eql(acl[:start])
51
- expect(j[0]["end"]).to eql(acl[:end])
52
- end
53
- it "should accept a JSON string" do
54
- params = Cloudinary::Uploader.build_upload_params access_control: acl_string
55
- expect(params).to have_key(:access_control)
56
- expect(params[:access_control]).to be_a String
57
- expect(params[:access_control]).to eql("[#{acl_string}]")
58
- end
59
- end
60
-
61
- describe 'upload' do
62
- break puts("Please setup environment for api test to run") if Cloudinary.config.api_secret.blank?
63
- include_context "cleanup", TIMESTAMP_TAG
64
-
65
- it 'should allow the user to define ACL in the upload parameters' do
66
- options[:access_control] = [acl]
67
- expect(RestClient::Request).to receive(:execute).with(
68
- deep_hash_value( {[:payload, :access_control] => "[#{acl_string}]"})
69
- ).and_call_original
70
- expect(resource).to have_key('access_control')
71
- response_acl = resource["access_control"]
72
- expect(response_acl.length).to be(1)
73
- expect(response_acl[0]["access_type"]).to eq("anonymous")
74
- expect(Time.parse(response_acl[0]["start"])).to eq(Time.parse(acl[:start]))
75
- expect(Time.parse(response_acl[0]["end"])).to eq(Time.parse(acl[:end]))
76
- end
77
- end
78
- describe 'update' do
79
- break puts("Please setup environment for api test to run") if Cloudinary.config.api_secret.blank?
80
- include_context "cleanup", TIMESTAMP_TAG
81
-
82
- it 'should allow the user to define ACL in the update parameters' do
83
- resource # upload before setting the expect
84
- expect(RestClient::Request).to receive(:execute).with(
85
- deep_hash_value( {[:payload, :access_control] => "[#{acl_string}]"})
86
- ).and_call_original
87
- result = Cloudinary::Api.update(
88
- resource['public_id'],
89
- :tags => [TEST_TAG, TIMESTAMP_TAG, 'access_control_test'],
90
- :access_control => acl)
91
- expect(result).to have_key('access_control')
92
- response_acl = result["access_control"]
93
- expect(response_acl.length).to be(1)
94
- expect(response_acl[0]["access_type"]).to eq("anonymous")
95
- expect(Time.parse(response_acl[0]["start"])).to eq(Time.parse(acl[:start]))
96
- expect(Time.parse(response_acl[0]["end"])).to eq(Time.parse(acl[:end]))
97
- end
98
- end
99
- end
data/spec/api_spec.rb DELETED
@@ -1,545 +0,0 @@
1
- require 'spec_helper'
2
- require 'cloudinary'
3
-
4
- describe Cloudinary::Api do
5
- break puts("Please setup environment for api test to run") if Cloudinary.config.api_secret.blank?
6
- include_context "cleanup", TIMESTAMP_TAG
7
- TEST_WIDTH = rand(1000)
8
- TEST_TRANSFOMATION = "c_scale,w_#{TEST_WIDTH}"
9
- prefix = "api_test_#{SUFFIX}"
10
- test_id_1 = "#{prefix}_1"
11
- test_id_2 = "#{prefix}_2"
12
- test_id_3 = "#{prefix}_3"
13
- test_key = "test_key_#{SUFFIX}"
14
- before(:all) do
15
-
16
- @api = Cloudinary::Api
17
- Cloudinary::Uploader.upload(TEST_IMG, :public_id => test_id_1, :tags => [TEST_TAG, TIMESTAMP_TAG], :context => "key=value", :eager =>[:width =>TEST_WIDTH, :crop =>:scale])
18
- Cloudinary::Uploader.upload(TEST_IMG, :public_id => test_id_2, :tags => [TEST_TAG, TIMESTAMP_TAG], :context => "key=value", :eager =>[:width =>TEST_WIDTH, :crop =>:scale])
19
- Cloudinary::Uploader.upload(TEST_IMG, :public_id => test_id_3, :tags => [TEST_TAG, TIMESTAMP_TAG], :context => "key=value", :eager =>[:width =>TEST_WIDTH, :crop =>:scale])
20
- Cloudinary::Uploader.upload(TEST_IMG, :public_id => test_id_1, :tags => [TEST_TAG, TIMESTAMP_TAG], :context => "#{test_key}=test", :eager =>[:width =>TEST_WIDTH, :crop =>:scale])
21
- Cloudinary::Uploader.upload(TEST_IMG, :public_id => test_id_3, :tags => [TEST_TAG, TIMESTAMP_TAG], :context => "#{test_key}=tasty", :eager =>[:width =>TEST_WIDTH, :crop =>:scale])
22
- end
23
-
24
- after(:all) do
25
- # in addition to "cleanup" context
26
- unless Cloudinary.config.keep_test_products
27
- up = Cloudinary::Api.upload_presets max_results: 500
28
- up["presets"].each do |u|
29
- tags = u["settings"]["tags"]
30
- name = u["name"]
31
- if tags =~ /.*#{TIMESTAMP_TAG}.*/
32
- Cloudinary::Api.delete_upload_preset(name)
33
- end
34
- end
35
- end
36
- end
37
-
38
- it "should allow listing resource_types" do
39
- expect(@api.resource_types()["resource_types"]).to include("image")
40
- end
41
-
42
- it "should allow listing resources" do
43
- resource = @api.resources()["resources"].find{|resource| resource["public_id"] == test_id_1
44
- }
45
- expect(resource).not_to be_blank
46
- expect(resource["type"]).to eq("upload")
47
- end
48
-
49
- it "should allow listing resources with cursor" do
50
- result = @api.resources(:max_results=>1)
51
- expect(result["resources"]).not_to be_blank
52
- expect(result["resources"].length).to eq(1)
53
- expect(result["next_cursor"]).not_to be_blank
54
- result2 = @api.resources(:max_results=>1, :next_cursor=>result["next_cursor"])
55
- expect(result2["resources"]).not_to be_blank
56
- expect(result2["resources"].length).to eq(1)
57
- expect(result2["resources"][0]["public_id"]).not_to eq(result["resources"][0]["public_id"] )
58
- end
59
-
60
- it "should allow listing resources by type" do
61
- resource = @api.resources(:type=>"upload", :tags=>true)["resources"].find{|resource| resource["public_id"] == test_id_1
62
- }
63
- expect(resource).not_to be_blank
64
- expect(resource["tags"]).to match_array([TEST_TAG, TIMESTAMP_TAG])
65
- end
66
-
67
- it "should allow listing resources by prefix" do
68
- resources = @api.resources(:type =>"upload", :prefix => prefix, :tags => true, :context => true)["resources"]
69
- expect(resources.map{|resource| resource["public_id"]}).to include(test_id_1, test_id_2)
70
- expect(resources.map{|resource| resource["tags"]}.flatten).to include(TEST_TAG, TIMESTAMP_TAG)
71
- expect(resources.map{|resource| resource["context"]}).to include({"custom" => {"key" => "value"}})
72
- end
73
-
74
- it "should allow listing resources by tag" do
75
- resources = @api.resources_by_tag(TEST_TAG, :tags => true, :context => true)["resources"]
76
- expect(resources.find{|resource| resource["public_id"] == test_id_1
77
- }).not_to be_blank
78
- expect(resources.map{|resource| resource["tags"]}.flatten).to include(TEST_TAG, TIMESTAMP_TAG)
79
- expect(resources.map{|resource| resource["context"]}).to include({"custom" => {"key" => "value"}})
80
- end
81
-
82
- it "should allow listing resources by context" do
83
- resources = @api.resources_by_context(test_key)["resources"]
84
- expect(resources.count).to eq(2)
85
- resources = @api.resources_by_context(test_key,'test')["resources"]
86
- expect(resources.count).to eq(1)
87
- end
88
-
89
- it "should allow listing resources by public ids" do
90
- resources = @api.resources_by_ids([test_id_1, test_id_2], :tags => true, :context => true)["resources"]
91
- expect(resources.length).to eq(2)
92
- expect(resources.find{|resource| resource["public_id"] == test_id_1
93
- }).not_to be_blank
94
- expect(resources.map{|resource| resource["tags"]}.flatten).to include(TEST_TAG, TIMESTAMP_TAG)
95
- expect(resources.map{|resource| resource["context"]}).to include({"custom" => {"key" => "value"}})
96
- end
97
-
98
- it "should allow listing resources by start date", :start_at => true do
99
- start_at = Time.now
100
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value( {[:payload, :start_at] => start_at, [:payload, :direction] => "asc"}))
101
- @api.resources(:type=>"upload", :start_at=>start_at, :direction => "asc")
102
- end
103
-
104
- describe ":direction" do
105
-
106
- it "should accept a string 'desc' and 'asc'" do
107
- expected = {
108
- :url => /.*\/resources\/image\/tags\/#{TIMESTAMP_TAG}/,
109
- [:payload, :direction] => "asc"
110
- }
111
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value(expected))
112
-
113
- @api.resources_by_tag(TIMESTAMP_TAG, :type=>"upload", :direction => "asc")
114
- end
115
- it "should accept an integer of '1' or '-1'" do
116
- expected = {
117
- :url => /.*\/resources\/image\/tags\/#{TIMESTAMP_TAG}/,
118
- [:payload, :direction] => "-1"
119
- }
120
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value(expected))
121
- @api.resources_by_tag(TIMESTAMP_TAG, :type=>"upload", :direction => "-1")
122
- end
123
- end
124
-
125
- it "should allow get resource metadata" do
126
- resource = @api.resource(test_id_1)
127
- expect(resource).not_to be_blank
128
- expect(resource["public_id"]).to eq(test_id_1)
129
- expect(resource["bytes"]).to eq(3381)
130
- expect(resource["derived"].length).to eq(1)
131
- end
132
-
133
- it "should allow deleting derived resource" do
134
- derived_resource_id = "derived_id"
135
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value( {[:payload, :derived_resource_ids] => derived_resource_id}))
136
- @api.delete_derived_resources(derived_resource_id)
137
- end
138
-
139
- it "should allow deleting derived resources by transformations" do
140
- public_id = "public_id"
141
- transformations = "c_crop,w_100"
142
- expect(RestClient::Request).to receive(:execute).with(
143
- deep_hash_value( {[:payload, :public_ids] => public_id,
144
- [:payload, :transformations] => "c_crop,w_100"}))
145
- @api.delete_derived_by_transformation(public_id, "c_crop,w_100")
146
-
147
- transformations = {:crop => "crop", :width => 100}
148
- expect(RestClient::Request).to receive(:execute).with(
149
- deep_hash_value( {[:payload, :public_ids] => public_id,
150
- [:payload, :transformations] => "c_crop,w_100"}))
151
- @api.delete_derived_by_transformation(public_id, transformations)
152
-
153
- transformations = [{:crop => "crop", :width => 100}, {:crop => "scale", :width => 300}]
154
- expect(RestClient::Request).to receive(:execute).with(
155
- deep_hash_value( {[:payload, :public_ids] => public_id,
156
- [:payload, :transformations] => "c_crop,w_100|c_scale,w_300"}))
157
- @api.delete_derived_by_transformation(public_id, transformations)
158
-
159
- end
160
-
161
- it "should allow deleting multiple resources and comma inclusive public IDs", :focus => true do
162
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value( {[:payload, :public_ids] => ["apit_test", "test_id_2", "api_test3"]}))
163
- @api.delete_resources(["apit_test", "test_id_2", "api_test3"])
164
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value( {[:payload, :public_ids] => "apit_test,test_id_2,api_test3"}))
165
- @api.delete_resources("apit_test,test_id_2,api_test3")
166
- end
167
-
168
- it "should allow deleting resource transformations" do
169
- resource = Cloudinary::Uploader.upload(TEST_IMG, :eager => [{:width=>101,:crop=>:scale}, {:width=>200,:crop=>:crop}])
170
- public_id = resource["public_id"]
171
- expect(resource).not_to be_blank
172
- derived = resource["eager"].map{|d| d["transformation"]}
173
- expect(derived).to include("c_scale,w_101", "c_crop,w_200")
174
- @api.delete_resources([public_id], :transformations => "c_crop,w_200")
175
- resource = @api.resource(public_id)
176
- derived = resource["derived"].map{|d| d["transformation"]}
177
- expect(derived).not_to include("c_crop,w_200")
178
- expect(derived).to include("c_scale,w_101")
179
- end
180
-
181
- it "should allow deleting resources by prefix" do
182
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value( {[:payload, :prefix] => "api_test_by"}))
183
- @api.delete_resources_by_prefix("api_test_by")
184
- end
185
-
186
- it "should allow deleting resources by tags" do
187
- expect(RestClient::Request).to receive(:execute).with(hash_including( :url => /.*\/tags\/api_test_tag_for_delete$/))
188
- @api.delete_resources_by_tag("api_test_tag_for_delete")
189
- end
190
-
191
- it "should allow listing tags" do
192
- tags = @api.tags(:max_results => 500)["tags"]
193
- expect(tags).to include(TEST_TAG)
194
- end
195
-
196
- it "should allow listing tag by prefix" do
197
- tags = @api.tags(:prefix=> TEST_TAG)["tags"]
198
- expect(tags).to include(TIMESTAMP_TAG)
199
- tags = @api.tags(:prefix=>"api_test_no_such_tag")["tags"]
200
- expect(tags).to be_blank
201
- end
202
-
203
- describe 'transformations' do
204
- it "should allow listing transformations" do
205
- transformation = @api.transformations(max_results: 500)["transformations"].find { |transformation| transformation["name"] == TEST_TRANSFOMATION }
206
- expect(transformation).not_to be_blank
207
- expect(transformation["used"]).to eq(true)
208
- end
209
-
210
- it "should allow getting transformation metadata" do
211
- transformation = @api.transformation(TEST_TRANSFOMATION)
212
- expect(transformation).not_to be_blank
213
- expect(transformation["info"]).to eq(["crop" => "scale", "width" => TEST_WIDTH])
214
- transformation = @api.transformation("crop" => "scale", "width" => TEST_WIDTH)
215
- expect(transformation).not_to be_blank
216
- expect(transformation["info"]).to eq(["crop" => "scale", "width" => TEST_WIDTH])
217
- end
218
-
219
- it "should allow updating transformation allowed_for_strict" do
220
- @api.update_transformation(TEST_TRANSFOMATION, :allowed_for_strict => true)
221
- transformation = @api.transformation(TEST_TRANSFOMATION)
222
- expect(transformation).not_to be_blank
223
- expect(transformation["allowed_for_strict"]).to eq(true)
224
- @api.update_transformation(TEST_TRANSFOMATION, :allowed_for_strict => false)
225
- transformation = @api.transformation(TEST_TRANSFOMATION)
226
- expect(transformation).not_to be_blank
227
- expect(transformation["allowed_for_strict"]).to eq(false)
228
- end
229
-
230
- it "should fetch two different derived images using next_cursor" do
231
- result = @api.transformation(TEST_TRANSFOMATION, :max_results=>1)
232
- expect(result["derived"]).not_to be_blank
233
- expect(result["derived"].length).to eq(1)
234
- expect(result["next_cursor"]).not_to be_blank
235
- result2 = @api.transformation(TEST_TRANSFOMATION, :max_results=>1, :next_cursor=>result["next_cursor"])
236
- expect(result2["derived"]).not_to be_blank
237
- expect(result2["derived"].length).to eq(1)
238
- expect(result2["derived"][0]["id"]).not_to eq(result["derived"][0]["id"] )
239
- end
240
-
241
- describe "named transformations" do
242
- it "should allow creating named transformation" do
243
- public_id = "api_test_transformation_#{Time.now.to_i}"
244
- @api.create_transformation(public_id, "crop" => "scale", "width" => 102)
245
- transformation = @api.transformation(public_id)
246
- expect(transformation).not_to be_blank
247
- expect(transformation["allowed_for_strict"]).to eq(true)
248
- expect(transformation["info"]).to eq(["crop" => "scale", "width" => 102])
249
- expect(transformation["used"]).to eq(false)
250
- end
251
-
252
- it "should allow deleting named transformation" do
253
- public_id = "api_test_transformation_#{Time.now.to_i}"
254
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value( :url => /.*\/transformations\/#{public_id}/, :method => :delete))
255
- @api.delete_transformation(public_id)
256
- end
257
-
258
- it "should allow unsafe update of named transformation" do
259
- public_id = "api_test_transformation_#{Time.now.to_i}"
260
- expected = {
261
- :url => /.*\/transformations\/#{public_id}$/,
262
- :method => :put,
263
- [:payload, :unsafe_update] => "c_scale,w_103"}
264
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value(expected))
265
- @api.update_transformation(public_id, :unsafe_update => { "crop" => "scale", "width" => 103 })
266
- end
267
-
268
- it "should allow listing of named transformations" do
269
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value( [:payload, :named ]=> true))
270
- @api.transformations :named => true
271
- end
272
-
273
- end
274
- it "should allow deleting implicit transformation" do
275
- @api.transformation(TEST_TRANSFOMATION)
276
- @api.delete_transformation(TEST_TRANSFOMATION)
277
- expect { @api.transformation(TEST_TRANSFOMATION) }.to raise_error(Cloudinary::Api::NotFound)
278
- end
279
- end
280
-
281
- it "should allow creating upload_presets" do
282
- expected = {:url => /.*\/upload_presets$/,
283
- [:payload, :name] => "new_preset",
284
- [:payload, :folder] => "some_folder"}
285
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value(expected))
286
-
287
- @api.create_upload_preset(:name => "new_preset", :folder => "some_folder", :tags => [TEST_TAG, TIMESTAMP_TAG])
288
- end
289
-
290
- describe "upload_presets" do
291
- it 'should not accept parameters' do
292
- expected = {
293
- :url => /.*\/upload_presets/,
294
- [:payload, :next_cursor] => 1234567,
295
- [:payload, :max_results] => 10
296
- }
297
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value(expected))
298
- @api.upload_presets :next_cursor => 1234567, :max_results => 10
299
-
300
- end
301
- end
302
- it "should allow getting a single upload_preset", :upload_preset => true do
303
- result = @api.create_upload_preset(:unsigned => true, :folder => "folder", :width => 100, :crop => :scale, :tags => ["a","b","c", TEST_TAG, TIMESTAMP_TAG], :context => {:a => "b", :c => "d"})
304
- name = result["name"]
305
- preset = @api.upload_preset(name)
306
- expect(preset["name"]).to eq(name)
307
- expect(preset["unsigned"]).to eq(true)
308
- expect(preset["settings"]["folder"]).to eq("folder")
309
- expect(preset["settings"]["transformation"]).to eq([{"width" => 100, "crop" => "scale"}])
310
- expect(preset["settings"]["context"]).to eq({"a" => "b", "c" => "d"})
311
- expect(preset["settings"]["tags"]).to eq(["a","b","c", TEST_TAG, TIMESTAMP_TAG])
312
- end
313
-
314
- it "should allow deleting upload_presets", :upload_preset => true do
315
- id = "#{prefix}_upload_preset"
316
- @api.create_upload_preset(:name => id, :folder => "folder", :tags => [TEST_TAG, TIMESTAMP_TAG])
317
- preset = @api.upload_preset(id)
318
- @api.delete_upload_preset(id)
319
- expect{preset = @api.upload_preset(id)}.to raise_error(Cloudinary::Api::NotFound)
320
- end
321
-
322
- it "should allow updating upload_presets", :upload_preset => true do
323
- name = @api.create_upload_preset(:folder => "folder", :tags => [TEST_TAG, TIMESTAMP_TAG])["name"]
324
- preset = @api.upload_preset(name)
325
- @api.update_upload_preset(name, preset["settings"].merge(:colors => true, :unsigned => true, :disallow_public_id => true))
326
- preset = @api.upload_preset(name)
327
- expect(preset["name"]).to eq(name)
328
- expect(preset["unsigned"]).to eq(true)
329
- expect(preset["settings"]).to eq({"folder" => "folder", "colors" => true, "disallow_public_id" => true, "tags" => [TEST_TAG, TIMESTAMP_TAG]})
330
- end
331
-
332
- # this test must be last because it deletes (potentially) all dependent transformations which some tests rely on. Excluded by default.
333
- skip "should allow deleting all resources", :delete_all=>true do
334
- Cloudinary::Uploader.upload(TEST_IMG, :public_id=>"api_test5", :eager=>[:width=>101,:crop=>:scale], :tags => [TEST_TAG, TIMESTAMP_TAG])
335
- resource = @api.resource("api_test5")
336
- expect(resource).not_to be_blank
337
- expect(resource["derived"].length).to eq(1)
338
- @api.delete_all_resources(:keep_original => true)
339
- resource = @api.resource("api_test5")
340
- expect(resource).not_to be_blank
341
- expect(resource["derived"].length).to eq(0)
342
- end
343
-
344
- it "should support setting manual moderation status" do
345
- result = Cloudinary::Uploader.upload(TEST_IMG, {:moderation => :manual, :tags => [TEST_TAG, TIMESTAMP_TAG]})
346
- expect(result["moderation"][0]["status"]).to eq("pending")
347
- expect(result["moderation"][0]["kind"]).to eq("manual")
348
- api_result = Cloudinary::Api.update(result["public_id"], {:moderation_status => :approved})
349
- expect(api_result["moderation"][0]["status"]).to eq("approved")
350
- expect(api_result["moderation"][0]["kind"]).to eq("manual")
351
- end
352
-
353
- it "should support requesting raw conversion" do
354
- result = Cloudinary::Uploader.upload("spec/docx.docx", :resource_type => :raw, :tags => [TEST_TAG, TIMESTAMP_TAG])
355
- expect{Cloudinary::Api.update(result["public_id"], {:resource_type => :raw, :raw_convert => :illegal})}.to raise_error(Cloudinary::Api::BadRequest, /^Illegal value|not a valid/)
356
- end
357
-
358
- it "should support requesting categorization" do
359
- result = Cloudinary::Uploader.upload(TEST_IMG, :tags => [TEST_TAG, TIMESTAMP_TAG])
360
- expect{Cloudinary::Api.update(result["public_id"], {:categorization => :illegal})}.to raise_error(Cloudinary::Api::BadRequest, /^Illegal value/)
361
- end
362
-
363
- it "should support requesting detection with server notification", :focus => true do
364
- expected = {
365
- [:payload, :detection] => "adv_face",
366
- [:payload, :notification_url] => "http://example.com"
367
- }
368
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value(expected))
369
- Cloudinary::Api.update("public_id", {:detection => "adv_face", :notification_url => "http://example.com"})
370
- end
371
-
372
- it "should support requesting auto_tagging" do
373
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value( [:payload, :auto_tagging] => 0.5))
374
- Cloudinary::Api.update("public_id", {:auto_tagging => 0.5})
375
- end
376
-
377
- it "should support listing by moderation kind and value" do
378
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value([:url] => /.*manual\/approved$/, [:payload, :max_results] => 1000))
379
- Cloudinary::Api.resources_by_moderation(:manual, :approved, :max_results => 1000)
380
- end
381
-
382
- it "should support listing folders" do
383
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value( [:url] => /.*\/folders$/, [:method] => :get))
384
- Cloudinary::Api.root_folders
385
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value( [:url] => /.*\/folders\/test_folder1$/, [:method] => :get))
386
- Cloudinary::Api.subfolders("test_folder1")
387
- end
388
-
389
- it "should throw if folder is missing" do
390
- expect{Cloudinary::Api.subfolders("I_do_not_exist")}.to raise_error(Cloudinary::Api::NotFound)
391
- end
392
-
393
- describe '.restore' do
394
- it 'should restore a deleted resource' do
395
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value( [:payload, :public_ids] => "api_test_restore", [:url] => /.*\/restore$/))
396
- Cloudinary::Api.restore("api_test_restore")
397
- end
398
- end
399
-
400
- describe 'create_upload_mapping' do
401
- mapping = "api_test_upload_mapping#{rand(100000)}"
402
- it 'should create mapping' do
403
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value( [:payload, :template] => "http://cloudinary.com"))
404
- Cloudinary::Api.create_upload_mapping(mapping, :template =>"http://cloudinary.com")
405
- expect(RestClient::Request).to receive(:execute).with(deep_hash_value( [:payload, :template] => "http://res.cloudinary.com"))
406
- Cloudinary::Api.update_upload_mapping(mapping, "template" =>"http://res.cloudinary.com")
407
- end
408
-
409
-
410
- end
411
- describe "access_mode" do
412
- i = 0
413
-
414
- publicId = ""
415
- access_mode_tag = ''
416
- before(:each) do
417
- i += 1
418
- access_mode_tag = TEST_TAG + "access_mode" + i.to_s
419
- result = Cloudinary::Uploader.upload TEST_IMG, access_mode: "authenticated", tags: [TEST_TAG, TIMESTAMP_TAG, access_mode_tag]
420
- publicId = result["public_id"]
421
- expect(result["access_mode"]).to eq("authenticated")
422
- end
423
-
424
- it "should update access mode by ids" do
425
- result = Cloudinary::Api.update_resources_access_mode_by_ids "public", [publicId]
426
-
427
- expect(result["updated"]).to be_an_instance_of(Array)
428
- expect(result["updated"].length).to eq(1)
429
- resource = result["updated"][0]
430
- expect(resource["public_id"]).to eq(publicId)
431
- expect(resource["access_mode"]).to eq('public')
432
- end
433
- it "should update access mode by prefix" do
434
- result = Cloudinary::Api.update_resources_access_mode_by_prefix "public", publicId[0..-3]
435
-
436
- expect(result["updated"]).to be_an_instance_of(Array)
437
- expect(result["updated"].length).to eq(1)
438
- resource = result["updated"][0]
439
- expect(resource["public_id"]).to eq(publicId)
440
- expect(resource["access_mode"]).to eq('public')
441
- end
442
- it "should update access mode by tag" do
443
- result = Cloudinary::Api.update_resources_access_mode_by_tag "public", access_mode_tag
444
-
445
- expect(result["updated"]).to be_an_instance_of(Array)
446
- expect(result["updated"].length).to eq(1)
447
- resource = result["updated"][0]
448
- expect(resource["public_id"]).to eq(publicId)
449
- expect(resource["access_mode"]).to eq('public')
450
- end
451
- end
452
-
453
- context "resource of type authenticated" do
454
- i = 0
455
- bytes = nil
456
- publicId = ""
457
- publish_resource_tag = "publish_resource_tag"
458
- before(:each) do
459
- i += 1
460
- result = Cloudinary::Uploader.upload TEST_IMG, type: "authenticated", tags: [TEST_TAG, TIMESTAMP_TAG, publish_resource_tag], transformation: {width: 100*i, crop: "scale"}
461
- publicId = result["public_id"]
462
- expect(result["type"]).to eq("authenticated")
463
- end
464
-
465
- it "should publish resources by ids" do
466
- result = Cloudinary::Api.publish_by_ids( [publicId])
467
-
468
- expect(result["published"]).to be_an_instance_of(Array)
469
- expect(result["published"].length).to eq(1)
470
-
471
- resource = result["published"][0]
472
-
473
- expect(resource["public_id"]).to eq(publicId)
474
- expect(resource["type"]).to eq('upload')
475
-
476
- bytes = resource["bytes"]
477
- end
478
- it "should publish resources by prefix and overwrite" do
479
- result = Cloudinary::Api.publish_by_prefix(publicId[0..-3], overwrite: true)
480
-
481
- expect(result["published"]).to be_an_instance_of(Array)
482
- expect(result["published"].length).to eq(1)
483
-
484
- resource = result["published"][0]
485
-
486
- expect(resource["public_id"]).to eq(publicId)
487
- expect(resource["bytes"]).not_to eq(bytes)
488
- expect(resource["type"]).to eq('upload')
489
-
490
- bytes = resource["bytes"]
491
- end
492
- it "should publish resources by tag and overwrite" do
493
- result = Cloudinary::Api.publish_by_tag(publish_resource_tag, overwrite: true)
494
-
495
- expect(result["published"]).to be_an_instance_of(Array)
496
- expect(result["published"].length).to eq(1)
497
-
498
- resource = result["published"][0]
499
-
500
- expect(resource["public_id"]).to eq(publicId)
501
- expect(resource["bytes"]).not_to eq(bytes)
502
- expect(resource["type"]).to eq('upload')
503
-
504
- bytes = resource["bytes"]
505
- end
506
- end
507
- end
508
-
509
- describe Cloudinary::Api::Response do
510
- let(:api_response) { described_class.new }
511
-
512
- shared_examples 'a Hash' do
513
- it 'inherits from Hash' do
514
- expect(api_response).to be_a Hash
515
- end
516
- end
517
-
518
- context 'when there is no argument given on instantiation' do
519
- it 'does not raise an error' do
520
- expect { api_response }.to_not raise_error
521
- end
522
-
523
- it_behaves_like 'a Hash'
524
- end
525
-
526
- context 'when the response is nil' do
527
- it 'does not raise an error' do
528
- expect { described_class.new nil }.to_not raise_error
529
- end
530
-
531
- it_behaves_like 'a Hash'
532
- end
533
-
534
- context 'when the response is present' do
535
- let(:body) { { 'foo' => 'bar' } }
536
- let(:http_response) { double code: 200, body: body.to_json, headers: { x_featureratelimit_reset: Time.new.to_s } }
537
- let(:api_response) { described_class.new http_response }
538
-
539
- it 'sets the instantiated self as the parsed response which is a Hash' do
540
- expect(api_response).to eq body
541
- end
542
-
543
- it_behaves_like 'a Hash'
544
- end
545
- end