Browse Source

open videos on popup overlay

Bachir Soussi Chiadmi 7 years ago
parent
commit
81f67414c8
100 changed files with 11338 additions and 0 deletions
  1. 369 0
      sites/all/libraries/jquery.domwindow/jquery.DOMWindow.js
  2. 116 0
      sites/all/modules/contrib/dev/libraries/CHANGELOG.txt
  3. 339 0
      sites/all/modules/contrib/dev/libraries/LICENSE.txt
  4. 38 0
      sites/all/modules/contrib/dev/libraries/README.txt
  5. 547 0
      sites/all/modules/contrib/dev/libraries/libraries.admin.inc
  6. 484 0
      sites/all/modules/contrib/dev/libraries/libraries.api.php
  7. 229 0
      sites/all/modules/contrib/dev/libraries/libraries.drush.inc
  8. 16 0
      sites/all/modules/contrib/dev/libraries/libraries.info
  9. 36 0
      sites/all/modules/contrib/dev/libraries/libraries.install
  10. 946 0
      sites/all/modules/contrib/dev/libraries/libraries.module
  11. 119 0
      sites/all/modules/contrib/dev/libraries/tests/LibrariesAdminWebTest.test
  12. 543 0
      sites/all/modules/contrib/dev/libraries/tests/LibrariesLoadWebTest.test
  13. 78 0
      sites/all/modules/contrib/dev/libraries/tests/LibrariesUnitTest.test
  14. 64 0
      sites/all/modules/contrib/dev/libraries/tests/LibrariesWebTestBase.test
  15. 43 0
      sites/all/modules/contrib/dev/libraries/tests/libraries/example/README.txt
  16. 12 0
      sites/all/modules/contrib/dev/libraries/tests/libraries/example/example_1.css
  17. 18 0
      sites/all/modules/contrib/dev/libraries/tests/libraries/example/example_1.js
  18. 15 0
      sites/all/modules/contrib/dev/libraries/tests/libraries/example/example_1.php
  19. 12 0
      sites/all/modules/contrib/dev/libraries/tests/libraries/example/example_2.css
  20. 18 0
      sites/all/modules/contrib/dev/libraries/tests/libraries/example/example_2.js
  21. 15 0
      sites/all/modules/contrib/dev/libraries/tests/libraries/example/example_2.php
  22. 12 0
      sites/all/modules/contrib/dev/libraries/tests/libraries/example/example_3.css
  23. 18 0
      sites/all/modules/contrib/dev/libraries/tests/libraries/example/example_3.js
  24. 12 0
      sites/all/modules/contrib/dev/libraries/tests/libraries/example/example_3.php
  25. 12 0
      sites/all/modules/contrib/dev/libraries/tests/libraries/example/example_4.css
  26. 18 0
      sites/all/modules/contrib/dev/libraries/tests/libraries/example/example_4.js
  27. 12 0
      sites/all/modules/contrib/dev/libraries/tests/libraries/example/example_4.php
  28. 10 0
      sites/all/modules/contrib/dev/libraries/tests/libraries/example_info_file.libraries.info
  29. 12 0
      sites/all/modules/contrib/dev/libraries/tests/modules/libraries_test_module/libraries_test_module.css
  30. 11 0
      sites/all/modules/contrib/dev/libraries/tests/modules/libraries_test_module/libraries_test_module.inc
  31. 13 0
      sites/all/modules/contrib/dev/libraries/tests/modules/libraries_test_module/libraries_test_module.info
  32. 18 0
      sites/all/modules/contrib/dev/libraries/tests/modules/libraries_test_module/libraries_test_module.js
  33. 631 0
      sites/all/modules/contrib/dev/libraries/tests/modules/libraries_test_module/libraries_test_module.module
  34. 15 0
      sites/all/modules/contrib/dev/libraries/tests/modules/libraries_test_module/libraries_test_module_post_load.inc
  35. 12 0
      sites/all/modules/contrib/dev/libraries/tests/themes/libraries_test_theme/libraries_test_theme.css
  36. 11 0
      sites/all/modules/contrib/dev/libraries/tests/themes/libraries_test_theme/libraries_test_theme.inc
  37. 11 0
      sites/all/modules/contrib/dev/libraries/tests/themes/libraries_test_theme/libraries_test_theme.info
  38. 18 0
      sites/all/modules/contrib/dev/libraries/tests/themes/libraries_test_theme/libraries_test_theme.js
  39. 36 0
      sites/all/modules/contrib/dev/libraries/tests/themes/libraries_test_theme/template.php
  40. 339 0
      sites/all/modules/contrib/fields/video_embed_field_overlay/LICENSE.txt
  41. 69 0
      sites/all/modules/contrib/fields/video_embed_field_overlay/README.txt
  42. 7 0
      sites/all/modules/contrib/fields/video_embed_field_overlay/css/video_embed_field_overlay.css
  43. 2 0
      sites/all/modules/contrib/fields/video_embed_field_overlay/images/README.txt
  44. BIN
      sites/all/modules/contrib/fields/video_embed_field_overlay/images/loading_128.png
  45. BIN
      sites/all/modules/contrib/fields/video_embed_field_overlay/images/loading_16.png
  46. BIN
      sites/all/modules/contrib/fields/video_embed_field_overlay/images/video_overlay.png
  47. 225 0
      sites/all/modules/contrib/fields/video_embed_field_overlay/js/video_embed_field_overlay.js
  48. 17 0
      sites/all/modules/contrib/fields/video_embed_field_overlay/video_embed_field_overlay.info
  49. 310 0
      sites/all/modules/contrib/fields/video_embed_field_overlay/video_embed_field_overlay.module
  50. 170 0
      sites/all/modules/contrib/files/imagecache_actions/CHANGELOG.txt
  51. 339 0
      sites/all/modules/contrib/files/imagecache_actions/LICENSE.txt
  52. 225 0
      sites/all/modules/contrib/files/imagecache_actions/README.txt
  53. 112 0
      sites/all/modules/contrib/files/imagecache_actions/ROADMAP.txt
  54. 13 0
      sites/all/modules/contrib/files/imagecache_actions/autorotate/imagecache_autorotate.info
  55. 25 0
      sites/all/modules/contrib/files/imagecache_actions/autorotate/imagecache_autorotate.install
  56. 235 0
      sites/all/modules/contrib/files/imagecache_actions/autorotate/imagecache_autorotate.module
  57. BIN
      sites/all/modules/contrib/files/imagecache_actions/autorotate/portrait-painting.jpg
  58. 1249 0
      sites/all/modules/contrib/files/imagecache_actions/canvasactions/canvasactions.inc
  59. 14 0
      sites/all/modules/contrib/files/imagecache_actions/canvasactions/imagecache_canvasactions.info
  60. 221 0
      sites/all/modules/contrib/files/imagecache_actions/canvasactions/imagecache_canvasactions.module
  61. 329 0
      sites/all/modules/contrib/files/imagecache_actions/canvasactions/rounded_corners.inc
  62. 115 0
      sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/cheap_dropshadow.imagecache_preset.inc
  63. BIN
      sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/cheap_dropshadow.jpg
  64. BIN
      sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/cheap_dropshadow.png
  65. 61 0
      sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/keyword_positioning.imagecache_preset.inc
  66. BIN
      sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/keyword_positioning.jpg
  67. 47 0
      sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/positioned_underlay.imagecache_preset.inc
  68. BIN
      sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/positioned_underlay.png
  69. 35 0
      sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/rotate_alpha.imagecache_preset.inc
  70. BIN
      sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/rotate_alpha.png
  71. 36 0
      sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/rotate_alpha_gif.imagecache_preset.inc
  72. 37 0
      sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/rotate_scale.imagecache_preset.inc
  73. BIN
      sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/rotate_scale.jpg
  74. 60 0
      sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/rotate_scale_alpha.imagecache_preset.inc
  75. BIN
      sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/rotate_scale_alpha.png
  76. 34 0
      sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/rounded.imagecache_preset.inc
  77. BIN
      sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/rounded.png
  78. 43 0
      sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/rounded_bl.imagecache_preset.inc
  79. BIN
      sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/rounded_bl.png
  80. 58 0
      sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/rounded_flattened.imagecache_preset.inc
  81. BIN
      sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/rounded_flattened.jpg
  82. BIN
      sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/shiny-bg.png
  83. 27 0
      sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/watermark_100.imagecache_preset.inc
  84. BIN
      sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/watermark_100.jpg
  85. 27 0
      sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/watermark_50.imagecache_preset.inc
  86. BIN
      sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/watermark_50.jpg
  87. 66 0
      sites/all/modules/contrib/files/imagecache_actions/coloractions/imagecache_coloractions.htaccess_creator.inc
  88. 18 0
      sites/all/modules/contrib/files/imagecache_actions/coloractions/imagecache_coloractions.info
  89. 12 0
      sites/all/modules/contrib/files/imagecache_actions/coloractions/imagecache_coloractions.install
  90. 1102 0
      sites/all/modules/contrib/files/imagecache_actions/coloractions/imagecache_coloractions.module
  91. 248 0
      sites/all/modules/contrib/files/imagecache_actions/coloractions/transparency.inc
  92. 145 0
      sites/all/modules/contrib/files/imagecache_actions/customactions/README.txt
  93. 14 0
      sites/all/modules/contrib/files/imagecache_actions/customactions/imagecache_customactions.info
  94. 23 0
      sites/all/modules/contrib/files/imagecache_actions/customactions/imagecache_customactions.install
  95. 290 0
      sites/all/modules/contrib/files/imagecache_actions/customactions/imagecache_customactions.module
  96. BIN
      sites/all/modules/contrib/files/imagecache_actions/docs/aspect-chaining.png
  97. BIN
      sites/all/modules/contrib/files/imagecache_actions/docs/brightness.png
  98. BIN
      sites/all/modules/contrib/files/imagecache_actions/docs/canvases.png
  99. BIN
      sites/all/modules/contrib/files/imagecache_actions/docs/cheap_dropshadow.png
  100. BIN
      sites/all/modules/contrib/files/imagecache_actions/docs/colorshift.png

+ 369 - 0
sites/all/libraries/jquery.domwindow/jquery.DOMWindow.js

@@ -0,0 +1,369 @@
+(function($){
+	
+	//closeDOMWindow
+	$.fn.closeDOMWindow = function(settings){
+		
+		if(!settings){settings={};}
+		
+		var run = function(passingThis){
+			
+			if(settings.anchoredClassName){
+				var $anchorClassName = $('.'+settings.anchoredClassName);
+				$anchorClassName.fadeOut('fast',function(){
+					if($.fn.draggable){
+						$anchorClassName.draggable('destory').trigger("unload").remove();	
+					}else{
+						$anchorClassName.trigger("unload").remove();
+					}
+				});
+				if(settings.functionCallOnClose){settings.functionCallAfterClose();}
+			}else{
+				var $DOMWindowOverlay = $('#DOMWindowOverlay');
+				var $DOMWindow = $('#DOMWindow');
+				$DOMWindowOverlay.fadeOut('fast',function(){
+					$DOMWindowOverlay.trigger('unload').unbind().remove();																	  
+				});
+				$DOMWindow.fadeOut('fast',function(){
+					if($.fn.draggable){
+						$DOMWindow.draggable("destroy").trigger("unload").remove();
+					}else{
+						$DOMWindow.trigger("unload").remove();
+					}
+				});
+			
+				$(window).unbind('scroll.DOMWindow');
+				$(window).unbind('resize.DOMWindow');
+				
+				if($.fn.openDOMWindow.isIE6){$('#DOMWindowIE6FixIframe').remove();}
+				if(settings.functionCallOnClose){settings.functionCallAfterClose();}
+			}	
+		};
+		
+		if(settings.eventType){//if used with $().
+			return this.each(function(index){
+				$(this).bind(settings.eventType, function(){
+					run(this);
+					return false;
+				});
+			});
+		}else{//else called as $.function
+			run();
+		}
+		
+	};
+	
+	//allow for public call, pass settings
+	$.closeDOMWindow = function(s){$.fn.closeDOMWindow(s);};
+	
+	//openDOMWindow
+	$.fn.openDOMWindow = function(instanceSettings){	
+		
+		var shortcut =  $.fn.openDOMWindow;
+	
+		//default settings combined with callerSettings////////////////////////////////////////////////////////////////////////
+		
+		shortcut.defaultsSettings = {
+			anchoredClassName:'',
+			anchoredSelector:'',
+			borderColor:'#ccc',
+			borderSize:'4',
+			draggable:0,
+			eventType:null, //click, blur, change, dblclick, error, focus, load, mousedown, mouseout, mouseup etc...
+			fixedWindowY:100,
+			functionCallOnOpen:null,
+			functionCallOnClose:null,
+			height:500,
+			loader:0,
+			loaderHeight:0,
+			loaderImagePath:'',
+			loaderWidth:0,
+			modal:0,
+			overlay:1,
+			overlayColor:'#000',
+			overlayOpacity:'85',
+			positionLeft:0,
+			positionTop:0,
+			positionType:'centered', // centered, anchored, absolute, fixed
+			width:500, 
+			windowBGColor:'#fff',
+			windowBGImage:null, // http path
+			windowHTTPType:'get',
+			windowPadding:10,
+			windowSource:'inline', //inline, ajax, iframe
+			windowSourceID:'',
+			windowSourceURL:'',
+			windowSourceAttrURL:'href'
+		};
+		
+		var settings = $.extend({}, $.fn.openDOMWindow.defaultsSettings , instanceSettings || {});
+		
+		//Public functions
+		
+		shortcut.viewPortHeight = function(){ return self.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;};
+		shortcut.viewPortWidth = function(){ return self.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;};
+		shortcut.scrollOffsetHeight = function(){ return self.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;};
+		shortcut.scrollOffsetWidth = function(){ return self.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft;};
+		shortcut.isIE6 = typeof document.body.style.maxHeight === "undefined";
+		
+		//Private Functions/////////////////////////////////////////////////////////////////////////////////////////////////////////
+		
+		var sizeOverlay = function(){
+			var $DOMWindowOverlay = $('#DOMWindowOverlay');
+			if(shortcut.isIE6){//if IE 6
+				var overlayViewportHeight = document.documentElement.offsetHeight + document.documentElement.scrollTop - 4;
+				var overlayViewportWidth = document.documentElement.offsetWidth - 21;
+				$DOMWindowOverlay.css({'height':overlayViewportHeight +'px','width':overlayViewportWidth+'px'});
+			}else{//else Firefox, safari, opera, IE 7+
+				$DOMWindowOverlay.css({'height':'100%','width':'100%','position':'fixed'});
+			}	
+		};
+		
+		var sizeIE6Iframe = function(){
+			var overlayViewportHeight = document.documentElement.offsetHeight + document.documentElement.scrollTop - 4;
+			var overlayViewportWidth = document.documentElement.offsetWidth - 21;
+			$('#DOMWindowIE6FixIframe').css({'height':overlayViewportHeight +'px','width':overlayViewportWidth+'px'});
+		};
+		
+		var centerDOMWindow = function() {
+			var $DOMWindow = $('#DOMWindow');
+			if(settings.height + 50 > shortcut.viewPortHeight()){//added 50 to be safe
+				$DOMWindow.css('left',Math.round(shortcut.viewPortWidth()/2) + shortcut.scrollOffsetWidth() - Math.round(($DOMWindow.outerWidth())/2));
+			}else{
+				$DOMWindow.css('left',Math.round(shortcut.viewPortWidth()/2) + shortcut.scrollOffsetWidth() - Math.round(($DOMWindow.outerWidth())/2));
+				$DOMWindow.css('top',Math.round(shortcut.viewPortHeight()/2) + shortcut.scrollOffsetHeight() - Math.round(($DOMWindow.outerHeight())/2));
+			}
+		};
+		
+		var centerLoader = function() {
+			var $DOMWindowLoader = $('#DOMWindowLoader');
+			if(shortcut.isIE6){//if IE 6
+				$DOMWindowLoader.css({'left':Math.round(shortcut.viewPortWidth()/2) + shortcut.scrollOffsetWidth() - Math.round(($DOMWindowLoader.innerWidth())/2),'position':'absolute'});
+				$DOMWindowLoader.css({'top':Math.round(shortcut.viewPortHeight()/2) + shortcut.scrollOffsetHeight() - Math.round(($DOMWindowLoader.innerHeight())/2),'position':'absolute'});
+			}else{
+				$DOMWindowLoader.css({'left':'50%','top':'50%','position':'fixed'});
+			}
+			
+		};
+		
+		var fixedDOMWindow = function(){
+			var $DOMWindow = $('#DOMWindow');
+			$DOMWindow.css('left', settings.positionLeft + shortcut.scrollOffsetWidth());
+			$DOMWindow.css('top', + settings.positionTop + shortcut.scrollOffsetHeight());
+		};
+		
+		var showDOMWindow = function(instance){
+			if(arguments[0]){
+				$('.'+instance+' #DOMWindowLoader').remove();
+				$('.'+instance+' #DOMWindowContent').fadeIn('fast',function(){if(settings.functionCallOnOpen){settings.functionCallOnOpen();}});
+				$('.'+instance+ '.closeDOMWindow').click(function(){
+					$.closeDOMWindow();	
+					return false;
+				});
+			}else{
+				$('#DOMWindowLoader').remove();
+				$('#DOMWindow').fadeIn('fast',function(){if(settings.functionCallOnOpen){settings.functionCallOnOpen();}});
+				$('#DOMWindow .closeDOMWindow').click(function(){						
+					$.closeDOMWindow();
+					return false;
+				});
+			}
+			
+		};
+		
+		var urlQueryToObject = function(s){
+			  var query = {};
+			  s.replace(/b([^&=]*)=([^&=]*)b/g, function (m, a, d) {
+				if (typeof query[a] != 'undefined') {
+				  query[a] += ',' + d;
+				} else {
+				  query[a] = d;
+				}
+			  });
+			  return query;
+		};
+			
+		//Run Routine ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+		var run = function(passingThis){
+			
+			//get values from element clicked, or assume its passed as an option
+			settings.windowSourceID = $(passingThis).attr('href') || settings.windowSourceID;
+			settings.windowSourceURL = $(passingThis).attr(settings.windowSourceAttrURL) || settings.windowSourceURL;
+			settings.windowBGImage = settings.windowBGImage ? 'background-image:url('+settings.windowBGImage+')' : '';
+			var urlOnly, urlQueryObject;
+			
+			if(settings.positionType == 'anchored'){//anchored DOM window
+				
+				var anchoredPositions = $(settings.anchoredSelector).position();
+				var anchoredPositionX = anchoredPositions.left + settings.positionLeft;
+				var anchoredPositionY = anchoredPositions.top + settings.positionTop;
+				
+				$('body').append('<div class="'+settings.anchoredClassName+'" style="'+settings.windowBGImage+';background-repeat:no-repeat;padding:'+settings.windowPadding+'px;overflow:auto;position:absolute;top:'+anchoredPositionY+'px;left:'+anchoredPositionX+'px;height:'+settings.height+'px;width:'+settings.width+'px;background-color:'+settings.windowBGColor+';border:'+settings.borderSize+'px solid '+settings.borderColor+';z-index:10001"><div id="DOMWindowContent" style="display:none"></div></div>');		
+				//loader
+				if(settings.loader && settings.loaderImagePath !== ''){
+					$('.'+settings.anchoredClassName).append('<div id="DOMWindowLoader" style="width:'+settings.loaderWidth+'px;height:'+settings.loaderHeight+'px;"><img src="'+settings.loaderImagePath+'" /></div>');
+					
+				}
+
+				if($.fn.draggable){
+					if(settings.draggable){$('.' + settings.anchoredClassName).draggable({cursor:'move'});}
+				}
+				
+				switch(settings.windowSource){
+					case 'inline'://////////////////////////////// inline //////////////////////////////////////////
+						$('.' + settings.anchoredClassName+" #DOMWindowContent").append($(settings.windowSourceID).children());
+						$('.' + settings.anchoredClassName).unload(function(){// move elements back when you're finished
+							$('.' + settings.windowSourceID).append( $('.' + settings.anchoredClassName+" #DOMWindowContent").children());				
+						});
+						showDOMWindow(settings.anchoredClassName);
+					break;
+					case 'iframe'://////////////////////////////// iframe //////////////////////////////////////////
+						$('.' + settings.anchoredClassName+" #DOMWindowContent").append('<iframe frameborder="0" hspace="0" wspace="0" src="'+settings.windowSourceURL+'" name="DOMWindowIframe'+Math.round(Math.random()*1000)+'" style="width:100%;height:100%;border:none;background-color:#fff;" class="'+settings.anchoredClassName+'Iframe" ></iframe>');
+						$('.'+settings.anchoredClassName+'Iframe').load(showDOMWindow(settings.anchoredClassName));
+					break;
+					case 'ajax'://////////////////////////////// ajax //////////////////////////////////////////	
+						if(settings.windowHTTPType == 'post'){
+							
+							if(settings.windowSourceURL.indexOf("?") !== -1){//has a query string
+								urlOnly = settings.windowSourceURL.substr(0, settings.windowSourceURL.indexOf("?"));
+								urlQueryObject = urlQueryToObject(settings.windowSourceURL);
+							}else{
+								urlOnly = settings.windowSourceURL;
+								urlQueryObject = {};
+							}
+							$('.' + settings.anchoredClassName+" #DOMWindowContent").load(urlOnly,urlQueryObject,function(){
+								showDOMWindow(settings.anchoredClassName);
+							});
+						}else{
+							if(settings.windowSourceURL.indexOf("?") == -1){ //no query string, so add one
+								settings.windowSourceURL += '?';
+							}
+							$('.' + settings.anchoredClassName+" #DOMWindowContent").load(
+								settings.windowSourceURL + '&random=' + (new Date().getTime()),function(){
+								showDOMWindow(settings.anchoredClassName);
+							});
+						}
+					break;
+				}
+				
+			}else{//centered, fixed, absolute DOM window
+				
+				//overlay & modal
+				if(settings.overlay){
+					$('body').append('<div id="DOMWindowOverlay" style="z-index:10000;display:none;position:absolute;top:0;left:0;background-color:'+settings.overlayColor+';filter:alpha(opacity='+settings.overlayOpacity+');-moz-opacity: 0.'+settings.overlayOpacity+';opacity: 0.'+settings.overlayOpacity+';"></div>');
+					if(shortcut.isIE6){//if IE 6
+						$('body').append('<iframe id="DOMWindowIE6FixIframe"  src="blank.html"  style="width:100%;height:100%;z-index:9999;position:absolute;top:0;left:0;filter:alpha(opacity=0);"></iframe>');
+						sizeIE6Iframe();
+					}
+					sizeOverlay();
+					var $DOMWindowOverlay = $('#DOMWindowOverlay');
+					$DOMWindowOverlay.fadeIn('fast');
+					if(!settings.modal){$DOMWindowOverlay.click(function(){$.closeDOMWindow();});}
+				}
+				
+				//loader
+				if(settings.loader && settings.loaderImagePath !== ''){
+					$('body').append('<div id="DOMWindowLoader" style="z-index:10002;width:'+settings.loaderWidth+'px;height:'+settings.loaderHeight+'px;"><img src="'+settings.loaderImagePath+'" /></div>');
+					centerLoader();
+				}
+
+				//add DOMwindow
+				$('body').append('<div id="DOMWindow" style="background-repeat:no-repeat;'+settings.windowBGImage+';overflow:auto;padding:'+settings.windowPadding+'px;display:none;height:'+settings.height+'px;width:'+settings.width+'px;background-color:'+settings.windowBGColor+';border:'+settings.borderSize+'px solid '+settings.borderColor+'; position:absolute;z-index:10001"></div>');
+				
+				var $DOMWindow = $('#DOMWindow');
+				//centered, absolute, or fixed
+				switch(settings.positionType){
+					case 'centered':
+						centerDOMWindow();
+						if(settings.height + 50 > shortcut.viewPortHeight()){//added 50 to be safe
+							$DOMWindow.css('top', (settings.fixedWindowY + shortcut.scrollOffsetHeight()) + 'px');
+						}
+					break;
+					case 'absolute':
+						$DOMWindow.css({'top':(settings.positionTop+shortcut.scrollOffsetHeight())+'px','left':(settings.positionLeft+shortcut.scrollOffsetWidth())+'px'});
+						if($.fn.draggable){
+							if(settings.draggable){$DOMWindow.draggable({cursor:'move'});}
+						}
+					break;
+					case 'fixed':
+						fixedDOMWindow();
+					break;
+					case 'anchoredSingleWindow':
+						var anchoredPositions = $(settings.anchoredSelector).position();
+						var anchoredPositionX = anchoredPositions.left + settings.positionLeft;
+						var anchoredPositionY = anchoredPositions.top + settings.positionTop;
+						$DOMWindow.css({'top':anchoredPositionY + 'px','left':anchoredPositionX+'px'});
+								
+					break;
+				}
+				
+				$(window).bind('scroll.DOMWindow',function(){
+					if(settings.overlay){sizeOverlay();}
+					if(shortcut.isIE6){sizeIE6Iframe();}
+					if(settings.positionType == 'centered'){centerDOMWindow();}
+					if(settings.positionType == 'fixed'){fixedDOMWindow();}
+				});
+
+				$(window).bind('resize.DOMWindow',function(){
+					if(shortcut.isIE6){sizeIE6Iframe();}
+					if(settings.overlay){sizeOverlay();}
+					if(settings.positionType == 'centered'){centerDOMWindow();}
+				});
+				
+				switch(settings.windowSource){
+					case 'inline'://////////////////////////////// inline //////////////////////////////////////////
+						$DOMWindow.append($(settings.windowSourceID).children());
+						$DOMWindow.unload(function(){// move elements back when you're finished
+							$(settings.windowSourceID).append($DOMWindow.children());				
+						});
+						showDOMWindow();
+					break;
+					case 'iframe'://////////////////////////////// iframe //////////////////////////////////////////
+						$DOMWindow.append('<iframe frameborder="0" hspace="0" wspace="0" src="'+settings.windowSourceURL+'" name="DOMWindowIframe'+Math.round(Math.random()*1000)+'" style="width:100%;height:100%;border:none;background-color:#fff;" id="DOMWindowIframe" ></iframe>');
+						$('#DOMWindowIframe').load(showDOMWindow());
+					break;
+					case 'ajax'://////////////////////////////// ajax //////////////////////////////////////////
+						if(settings.windowHTTPType == 'post'){
+							
+							if(settings.windowSourceURL.indexOf("?") !== -1){//has a query string
+								urlOnly = settings.windowSourceURL.substr(0, settings.windowSourceURL.indexOf("?"));
+								urlQueryObject = urlQueryToObject(settings.windowSourceURL);
+							}else{
+								urlOnly = settings.windowSourceURL;
+								urlQueryObject = {};
+							}
+							$DOMWindow.load(urlOnly,urlQueryObject,function(){
+								showDOMWindow();
+							});
+						}else{
+							if(settings.windowSourceURL.indexOf("?") == -1){ //no query string, so add one
+								settings.windowSourceURL += '?';
+							}
+							$DOMWindow.load(
+								settings.windowSourceURL + '&random=' + (new Date().getTime()),function(){
+								showDOMWindow();
+							});
+						}
+					break;
+				}
+				
+			}//end if anchored, or absolute, fixed, centered
+			
+		};//end run()
+		
+		if(settings.eventType){//if used with $().
+			return this.each(function(index){				  
+				$(this).bind(settings.eventType,function(){
+					run(this);
+					return false;
+				});
+			});	
+		}else{//else called as $.function
+			run();
+		}
+		
+	};//end function openDOMWindow
+	
+	//allow for public call, pass settings
+	$.openDOMWindow = function(s){$.fn.openDOMWindow(s);};
+	
+})(jQuery);

+ 116 - 0
sites/all/modules/contrib/dev/libraries/CHANGELOG.txt

@@ -0,0 +1,116 @@
+
+Libraries 7.x-2.3, 2016-05-12
+-----------------------------
+#1884246 by BR0kEN, tstoeckler et al: Allow downloading libraries via Drush.
+by tstoeckler: Allow detecting all libraries by calling libraries_detect().
+by tstoeckler: Prevent LibrariesWebTestBase from being displayed in the UI.
+#819610 by tstoeckler: Add tests for the Libraries UI.
+#1884246 by BR0kEN, tstoeckler: Show the provider in drush libraries-list
+#819610 by Pol, tstoeckler: Show the provider in the UI.
+#2634732 by Rob Holmes, tstoeckler: Sort libraries by title in the UI.
+#2585395 by robinsonsarah01: Allow object methods as version callbacks.
+#819610 by tstoeckler, Pol: Provide a status report for library information.
+#2352251 by netw3rker: Fix incorrect hook name in libraries.api.php.
+#2352237 by netw3rker, tstoeckler: Allow clearing the libraries cache from Drush.
+#2193969 by tstoeckler: Avoid warnings for stale library caches.
+#2287529 by drupalshrek, tstoeckler: Update installation link in README.txt.
+
+Libraries 7.x-2.2, 2014-02-09
+-----------------------------
+#2046919 by tstoeckler: Clarify 'version' docs.
+#1946110 by munroe_richard: Allow uppercase letters as library machine names.
+#1953260 by tstoeckler: Improve documentation of libraries_get_version().
+#1855918 by tstoeckler: Make integration file loading backwards-compatible.
+#1876124 by tstoeckler: Fix integration files for themes.
+#1876124 by tstoeckler: Add tests for theme-provided library information.
+#1876124 by tstoeckler: Prepare for adding a test theme.
+#1876124 by tstoeckler | whastings, fubhy: Fix hook_libraries_info() for themes.
+#2015721 by tstoeckler, CaptainHook: Protect against files overriding local variables.
+#2046919 by tstoeckler: Improve documentation around 'version callback'.
+#1844272 by tstoeckler, jweowu: Fix typos in libraries.api.php.
+#1938638 by tstoeckler: Prevent weird PHP notice on update.
+#1329388 by RobLoach, tstoeckler: Clear static caches in libraries_flush_caches().
+#1855918 by rbayliss: Load integration files after library files.
+#1938638 by Pol: Fix typo in libraries.api.php.
+
+Libraries 7.x-2.1, 2013-03-09
+-----------------------------
+#1937446 by Pol, tstoeckler: Add a 'pre-dependencies-load' callback group.
+#1775668 by tstoeckler: Fix bogus assertion message in assertLibraryFiles().
+#1773640 by tstoeckler: Use drupal_get_path() to find the profile directory.
+#1565426 by tstoeckler: Invoke hook_libraries_info() in enabled themes.
+
+Libraries 7.x-2.0, 2012-07-29
+-----------------------------
+#1606018 by chemical: Tests fail if the module is downloaded from Drupal.org.
+#1386250 by tstoeckler: Clarify module and library installation in README.txt.
+#1578618 by iamEAP: Fixed Fatal cache flush failure on major version upgrades.
+#1449346 by tstoeckler, sun: Clean-up libraries.test
+
+Libraries 7.x-2.0-alpha2, 2011-12-15
+------------------------------------
+#1299076 by tstoeckler: Improve testing of JS, CSS, and PHP files.
+#1347214 by rfay: Improve update function 7200.
+#1323530 by tstoeckler: Document libraries_get_version() pattern matching.
+#1325524 by sun, Rob Loach, tstoeckler: Statically cache libraries_detect().
+#1321372 by Rob Loach: Provide a 'post-load' callback group.
+#1205854 by tstoeckler, sun: Test library caching.
+
+Libraries 7.x-2.0-alpha1, 2011-10-01
+------------------------------------
+#1268342 by tstoeckler: Clean up drush libraries-list command.
+#962214 by tstoeckler, sun: Add support for library dependencies.
+#1224838 by sun, mjpa: Fix library path not being prepended to JS/CSS files.
+#1023258 by tstoeckler: Make 'files' consistently keyed by filename.
+#958162 by sun, tstoeckler: Add pre-detect callback group.
+#958162 by sun, tstoeckler: Make tests debuggable and provide libraries_info_defaults().
+#961476 by tstoeckler: Changed libraries_get_path() to return FALSE by default.
+#958162 by tstoeckler, sun, good_man: Allow to apply callbacks to libraries.
+#1125904 by tstoeckler, boombatower: Fix drush libraries-list.
+#1050076 by tstoeckler: Re-utilize libraries_detect() and remove libraries_detect_library().
+#466090 by tstoeckler: Add update function.
+#466090 by tstoeckler: Allow cache to be flushed.
+#466090 by tstoeckler, sun: Cache library information.
+#1064008 by tstoeckler, bfroehle: Fix outdated API examples in libraries.api.php.
+#1028744 by tstoeckler: Code clean-up.
+#1023322 by tstoeckler, sun: Fixed libraries shouldn't be loaded multiple times.
+#1024080 by hswong3i, tstoeckler: Fixed installation profile retrieval.
+#995988 by good_man: Wrong default install profile.
+#975498 by Gábor Hojtsy: Update JS/CSS-loading to new drupal_add_js/css() API.
+#958162 by tsteoeckler, sun: Consistent variable naming.
+#924130 by aaronbauman: Fixed libraries_get_path() should use drupal_static().
+#958162 by tstoeckler, sun: Code clean-up, tests revamp, more robust loading.
+#919632 by tstoeckler, sun: Allow library information to be stored in info files.
+by sun: Fixed testbot breaks upon directory name/info file name mismatch.
+#864376 by tstoeckler, sun: Code-cleanup, allow hard-coded 'version'.
+#939174 by sun, tstoeckler: Rename example.info to libraries_example.info.
+by sun: Fixed testbot breaks upon .info file without .module file.
+#542940 by tstoeckler, sun: Add libraries-list command.
+#919632 by tstoeckler: Add example library info file for testing purposes.
+#719896 by tstoeckler, sun: Documentation clean-up and tests improvement.
+#542940 by sun: Added initial Drush integration file.
+#719896 by tstoeckler, sun: Improved library detection and library loading.
+#855050 by Gábor Hojtsy: Avoid call-time pass by reference in libraries_detect().
+#719896 by tstoeckler, sun: Added starting point for hook_libraries_info().
+
+
+Libraries 7.x-1.x, xxxx-xx-xx
+-----------------------------
+
+Libraries 7.x-1.0, 2010-01-27
+-----------------------------
+#743522 by sun: Ported to D7.
+
+
+Libraries 6.x-1.x, xxxx-xx-xx
+-----------------------------
+
+Libraries 6.x-1.0, 2010-01-27
+-----------------------------
+#1028744 by tstoeckler: Code clean-up.
+#496732 by tstoeckler, robphillips: Allow placing libraries in root directory.
+
+Libraries 6.x-1.0-alpha1, 2009-12-30
+------------------------------------
+#480440 by markus_petrux: Fixed base_path() not applied to default library path.
+#320562 by sun: Added basic functions.

+ 339 - 0
sites/all/modules/contrib/dev/libraries/LICENSE.txt

@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.

+ 38 - 0
sites/all/modules/contrib/dev/libraries/README.txt

@@ -0,0 +1,38 @@
+
+-- SUMMARY --
+
+Libraries API provides external library handling for Drupal modules.
+
+For a full description visit the project page:
+  http://drupal.org/project/libraries
+Bug reports, feature suggestions and latest developments:
+  http://drupal.org/project/issues/libraries
+
+
+-- REQUIREMENTS --
+
+* None.
+
+
+-- INSTALLATION --
+
+* Install as usual, see
+  https://www.drupal.org/documentation/install/modules-themes/modules-7 for
+  further information. Note that installing external libraries is separate from
+  installing this module and should happen in the sites/all/libraries directory.
+  See http://drupal.org/node/1440066 for more information.
+
+
+-- CONTACT --
+
+Current maintainers:
+* Daniel F. Kudwien (sun) - http://drupal.org/user/54136
+* Tobias Stöckler (tstoeckler) - http://drupal.org/user/107158
+
+
+This project has been sponsored by:
+* UNLEASHED MIND
+  Specialized in consulting and planning of Drupal powered sites, UNLEASHED
+  MIND offers installation, development, theming, customization, and hosting
+  to get you started. Visit http://www.unleashedmind.com for more information.
+

+ 547 - 0
sites/all/modules/contrib/dev/libraries/libraries.admin.inc

@@ -0,0 +1,547 @@
+<?php
+
+/**
+ * @file
+ * Provides administrative page and form callbacks for Libraries module.
+ */
+
+/**
+ * Form generation callback for the libraries overview table.
+ *
+ * This is a form instead of a page to allow easier extending in contributed
+ * modules.
+ *
+ * @param array $form
+ *   An associative array containing the structure of the form.
+ * @param array $form_state
+ *   A keyed array containing the current state of the form.
+ *
+ * @return array
+ *   The form array for the overview form.
+ */
+function libraries_admin_overview(array $form, array &$form_state) {
+  $header = array(t('Name'), t('Status'), t('Installed version'), t('Provider'), t('Links'));
+  $rows = array();
+
+  $libraries = libraries_detect();
+  uasort($libraries, 'libraries_admin_sort_title');
+
+  foreach ($libraries as $machine_name => $library) {
+    $actions = array();
+
+    if ($library['vendor url']) {
+      $actions[] = l('Homepage', $library['vendor url']);
+    }
+    if ($library['download url']) {
+      $actions[] = l('Download', $library['download url']);
+    }
+
+    $rows[] = array(
+      'data' => array(
+        l($library['name'], 'admin/reports/libraries/' . $machine_name),
+        ($library['installed'] ? t('OK') : drupal_ucfirst($library['error'])),
+        (isset($library['version']) ? $library['version'] : ''),
+        libraries_admin_get_provider_with_type($library),
+        implode(' | ', $actions),
+      ),
+      'class' => ($library['installed'] ? array('ok') : array('error')),
+    );
+  }
+
+  $form['libraries']['list'] = array(
+    '#theme' => 'table',
+    '#header' => $header,
+    '#rows' => $rows,
+    '#empty' => t('There are currently no libraries installed'),
+  );
+
+  return $form;
+}
+
+/**
+ * Form generation callback for the status overview for a single library.
+ *
+ * This is a form instead of a page to allow easier extending in contributed
+ * modules.
+ *
+ * @param array $form
+ *   An associative array containing the structure of the form.
+ * @param array $form_state
+ *   A keyed array containing the current state of the form.
+ * @param array $library
+ *   A library information array.
+ *
+ * @return array|null
+ *   The form array for the status form or NULL if the library was not found.
+ *
+ * @todo Add some var_export($library)-style output
+ */
+function libraries_admin_library_status_form(array $form, array &$form_state, $library) {
+  drupal_set_title(t('Status report for library %library', array('%library' => $library['name'])), PASS_THROUGH);
+
+  if ($library['installed']) {
+    drupal_set_message(t('The %name library is installed correctly.', array('%name' => $library['name'])));
+    $form['status'] = libraries_admin_status_table($library);
+  }
+  else {
+    drupal_set_message($library['error message'], 'error');
+    switch ($library['error']) {
+      case 'not found':
+        $form['instructions'] = libraries_admin_instructions_missing($library);
+        break;
+
+      case 'not detected':
+        $form['instructions'] = libraries_admin_instructions_undetected($library);;
+        break;
+
+      case 'not supported':
+        $form['instructions'] = libraries_admin_instructions_unsupported($library);
+        break;
+
+      case 'missing dependency':
+        $form['instructions']['instruction']['#markup'] = t('There a missing dependency in your configuration that prevent this library to work properly.') . '<br>';
+        break;
+
+      case 'incompatible dependency':
+        $form['instructions']['instruction']['#markup'] = t('There an incompatible dependency in your configuration that prevent this library to work properly.') . '<br>';
+        break;
+    }
+  }
+
+  return $form;
+}
+
+
+/**
+ * Displays a table of status information about a library.
+ *
+ * @param array $library
+ *   A library information array.
+ *
+ * @return array
+ *   A renderable array containing a table with status information.
+ */
+function libraries_admin_status_table(array $library) {
+  $header = array(array(
+    // @todo The title implies that other type of information is displayed, as
+    //   well, but this is currently not the case.
+    // @todo Use CSS instead of a <strong> element.
+    'data' => '<strong>' . t('General information') . '</strong>',
+    'colspan' => 2,
+    'class' => 'table-heading',
+    'no_striping' => TRUE,
+  ));
+
+  $rows = array();
+  // @todo Use CSS instead of <strong> elements.
+  $rows['name'] = array('<strong>' . t('Name') . '</strong>', check_plain($library['name']));
+  $rows['machine_name'] = array('<strong>' . t('Machine name') . '</strong>', check_plain($library['machine name']));
+  if ($library['vendor url']) {
+    $rows['vendor_url'] = array('<strong>' . t('Vendor URL') . '</strong>', l($library['vendor url'], $library['vendor url']));
+  }
+  if ($library['download url']) {
+    $rows['download_url'] = array('<strong>' . t('Download URL') . '</strong>', l($library['download url'], $library['download url']));
+  }
+  $rows['provider'] = array('<strong>' . t('Provider') . '</strong>', libraries_admin_get_provider_with_type($library));
+  $rows['library_path'] = array('<strong>' . t('Library path') . '</strong>', $library['library path']);
+  $rows['version'] = array('<strong>' . t('Version') . '</strong>', $library['version']);
+  if (!empty($library['variants'])) {
+    $rows['variants'] = array('<strong>' . t('Variants') . '</strong>', implode(', ', array_keys($library['variants'])));
+  }
+
+  return array(
+    '#theme' => 'table',
+    '#header' => $header,
+    '#rows' => $rows,
+  );
+}
+
+/**
+ * Returns instructions for dealing with a missing library.
+ *
+ * @param array $library
+ *   A library information array.
+ *
+ * @return array
+ *   A renderable array containing the instructions.
+ */
+function libraries_admin_instructions_missing(array $library) {
+  $build = array();
+
+  $build['instruction']['#markup'] = t('Follow these steps to install the library:');
+
+  $items = array();
+  // 1. Download the library.
+  // If no supported versions are specified, the latest version is
+  // recommended.
+  if (empty($library['versions'])) {
+    $items[] = t('Download the latest version of the library <a href="@download-url">here</a>.', array(
+      '@download-url' => $library['download url'],
+    ));
+  }
+  // Otherwise, the latest supported version is recommended.
+  else {
+    $versions = array_keys($library['versions']);
+    usort($versions, 'version_compare');
+    $versions = array_reverse($versions);
+    $version = $versions[0];
+    $items[] = t('Download version %version of the library <a href="@download-url">here</a>.', array(
+      '%version' => $version,
+      '@download-url' => $library['download url'],
+    ));
+  }
+  // 2. Unpack it.
+  $items[] = t('If the library is an archive, i.e. if the file ending is for example <em>.tar.gz</em> or <em>.zip</em>, unpack it.');
+  // 3. Create the libraries folder.
+  $items[] = t('In the %library-directory directory of your Drupal installation create a %library directory.', array(
+    '%library-directory' => 'sites/all/libraries',
+    '%library' => $library['machine name'],
+  ));
+  // 4. Upload it.
+  // If the library has variant-independent files, give the user the
+  // location of an example file to check his filesystem against.
+  if ($directory_layout = libraries_admin_directory_layout($library)) {
+    $items[] = t('Upload the whole library (which can consist of multiple directories) into the newly created %library-path directory. The following files and directories should be contained in that directory: !directory-layout', array(
+      '%library-path' => 'sites/all/libraries/' . $library['machine name'],
+      '!directory-layout' => drupal_render($directory_layout),
+    ));
+  }
+  else {
+    $items[] = t('Upload the whole library (which can consist of multiple directories) into the newly created %library-path directory.', array(
+      '%library-path' => 'sites/all/libraries/' . $library['machine name'],
+    ));
+  }
+  // 5. Reload.
+  $items[] = t('<a href="">Reload</a> the page. If successful, you should see status information about this library.');
+
+  $build['steps'] = array(
+    '#theme' => 'item_list',
+    '#items' => $items,
+    '#type' => 'ol'
+  );
+
+  return $build;
+}
+
+
+/**
+ * Returns instructions for dealing with an undetected library.
+ *
+ * @param array $library
+ *   A library information array.
+ *
+ * @return array
+ *   A renderable array containing the instructions.
+ */
+function libraries_admin_instructions_undetected($library) {
+  $build = array();
+  // Re-check location.
+  // @todo Avoid usage of <br> elements.
+  $build['instruction']['#markup'] = t('Check that the whole library is located at %library-path.', array(
+      '%library-path' => $library['library path'],
+    )) . '<br>';
+  // If the library has variant-independent files, give the user the
+  // exact location of the files to check against.
+  // @todo It should be possible to display even variant-specific files
+  //   in case the variant is installed, but libraries_detect() does not
+  //   detect variants if the library version cannot be detected.
+  if ($directory_layout = libraries_admin_directory_layout($library)) {
+    $build['directory_layout'] = $directory_layout;
+    $build['directory_layout']['#prefix'] = t('The following files and directories should be contained in that directory:');
+  }
+
+  // If the library is placed correctly the library information is
+  // incorrect.
+  // This switch could be avoided by using $library['info type'], but that would
+  // hinder properly translating these strings.
+  $build['reload']['#markup'] = t('If you have moved any files, <a href="">reload</a> the page. If successful, you should see status information about this library.') . '<br>';
+  $build['notice']['#markup'] = t('If the files are placed correctly and the version can still not be detected, the library information is incorrect.') . '<br>';
+
+  $provider = libraries_admin_get_provider($library);
+  switch ($library['info type']) {
+    case 'module':
+      $build['contact']['#markup'] = t('Contact the maintainer of the %module module to correct this.', array(
+          '%module' => $provider,
+        )) . '<br>';
+      break;
+
+    case 'theme':
+      $build['contact']['#markup'] = t('Contact the maintainer of the %theme theme to correct this.', array(
+          '%theme' => $provider,
+        )) . '<br>';
+      break;
+
+    case 'info file':
+      $build['contact']['#markup'] = t('Contact the maintainer of the %info-file info file to correct this.', array(
+          '%info-file' => $provider,
+        )) . '<br>';
+      break;
+  }
+  return $build;
+}
+
+
+/**
+ * Returns instructions for dealing with an unsupported library.
+ *
+ * @param array $library
+ *   A library information array.
+ *
+ * @return array
+ *   A renderable array containing the instructions.
+ */
+function libraries_admin_instructions_unsupported($library) {
+  $build = array();
+  $items = array();
+
+  // Either download a different version of the library...
+  $versions = array_keys($library['versions']);
+  usort($versions, 'version_compare');
+  $versions = array_reverse($versions);
+  $version = $versions[0];
+  $build['instruction']['#markup'] = t('Please install version %version of the library by following the following steps:',
+    array(
+      '%version' => $version,
+    ));
+  // 1. Delete the old library.
+  $items[] = t('Delete the entire contents of the %library-path directory.',
+    array(
+      '%library-path' => $library['library path'],
+    ));
+  // 2. Download the new library.
+  $items[] = t('Download version %version of the library <a href="@download-url">here</a>.',
+    array(
+      '%version' => $version,
+      '@download-url' => $library['download url'],
+    ));
+  // 3. Unpack it.
+  $items[] = t('If the library is an archive, i.e. if the file ending is for example <em>.tar.gz</em> or <em>.zip</em>, unpack it.');
+  // 4. Upload the new library.
+  // If the library has variant-independent files, give the user the
+  // location of an example file to check his filesystem against.
+  if ($directory_layout = libraries_admin_directory_layout($library)) {
+    $items[] = t('Upload the new files into the %library-path directory. The following files and directories should be contained in that directory: !directory-layout',
+      array(
+        '%library-path' => $library['library path'],
+        '!directory-layout' => drupal_render($directory_layout),
+      ));
+  }
+  else {
+    $items[] = t('Upload the new files into the %library-path directory.',
+      array(
+        '%library-path' => $library['library path'],
+      ));
+  }
+  // 5. Reload.
+  $items[] = t('<a href="">Reload</a> the page. If successful, you should see status information about this library.');
+  $build['steps'] = array(
+    '#theme' => 'item_list',
+    '#items' => $items,
+    '#type' => 'ol',
+  );
+  // ...or contact the maintainer of the library information.
+  $provider = libraries_admin_get_provider($library);
+  switch ($library['info type']) {
+    case 'module':
+      $build['contact']['#markup'] = t('If you are bound to version @version of the library, ask the maintainer of the %module module to provide support for it.', array(
+          '@version' => $library['version'],
+          '%module' => $provider,
+        )) . '<br>';
+      break;
+
+    case 'theme':
+      $build['contact']['#markup'] = t('If you are bound to version @version of the library, ask the maintainer of the %theme theme to provide support for it.', array(
+          '@version' => $library['version'],
+          '%theme' => $provider,
+        )) . '<br>';
+      break;
+
+    case 'info file':
+      $build['contact']['#markup'] = t('If you are bound to version @version of the library, ask the maintainer of the %info-file info file to provide support for it.', array(
+          '@version' => $library['version'],
+          '%info-file' => $provider,
+        )) . '<br>';
+      break;
+  }
+  return $build;
+}
+
+/**
+ * Returns the directory layout of the library, if possible.
+ *
+ * The result of this function can help users to verify that they have uploaded
+ * the library to the correct location.
+ *
+ * @param array $library
+ *   A library information array.
+ *
+ * @return array|false
+ *   A renderable array containing the directory layout of the library or FALSE
+ *   if a directory layout could not be generated.
+ */
+function libraries_admin_directory_layout(array $library) {
+  $build = array(
+    '#theme' => 'item_list',
+    '#type' => 'ul',
+    '#items' => array(),
+  );
+
+  $items = &$build['#items'];
+  if ($library['path']) {
+    $items = &libraries_admin_path_to_tree($items, $library['path']);
+  }
+  foreach (array('js', 'css', 'php') as $type) {
+    if (!empty($library['files'][$type])) {
+      $files = array_keys($library['files'][$type]);
+      foreach ($files as $file) {
+        // Skip JavaScript settings.
+        if (is_int($file)) {
+          continue;
+        }
+
+        $children = &$items;
+        libraries_admin_path_to_tree($children, $file);
+      }
+    }
+  }
+  return $build['#items'] ? $build : FALSE;
+}
+
+/**
+ * Converts a file path into a tree structure for use in an item list.
+ *
+ * For example, the path 'foo/bar/baz' will be converted into the tree structure
+ * represented by the following list:
+ * - foo
+ *   - bar
+ *     - baz
+ *
+ * The $items array that is modified by reference or returned (see below) can
+ * be used as the 'items' variable for theme_item_list().
+ *
+ * This function modifies passed-in $items array, so that multiple paths can
+ * be placed into the same tree structure easily.
+ *
+ * @code
+ *   $items = array();
+ *   foreach ($paths as $path) {
+ *     libraries_admin_path_to_tree($items, $path);
+ *   }
+ * @endcode
+ *
+ * It also returns the last item by reference, so that it can also be used to
+ * traverse into a sub-structure and add further children there.
+ *
+ * @code
+ *   $items = array();
+ *   $children = &libraries_admin_path_to_tree($items, $path);
+ *   foreach ($sub_paths as $sub_path) {
+ *     libraries_admin_path_to_tree($children, $sub_path);
+ *   }
+ * @endcode
+ *
+ * @param array $items
+ * @param string $path
+ *
+ * @return array
+ */
+function &libraries_admin_path_to_tree(array &$items, $path) {
+  $part = strtok($path, '/');
+  while ($part) {
+    if (!isset($items[$part])) {
+      $items[$part] = array(
+        'data' => $part,
+        'children' => array(),
+      );
+    }
+    $items = &$items[$part]['children'];
+    $part = strtok('/');
+  }
+
+  return $items;
+}
+
+/**
+ * Sorts libraries by name.
+ *
+ * This function can be used as a callback for usort() or uasort().
+ *
+ * @param array $a
+ *   The first library information array.
+ * @param array $b
+ *   The second library information array.
+ *
+ * @return int
+ *   Returns -1 if $a is considered smaller than $b, 1 if $a considered greater
+ *   than $b and 0 if $a and $b are considered equal.
+ *
+ * @see strnatcasecmp()
+ * @see usort()
+ * @see uasort()
+ */
+function libraries_admin_sort_title(array $a, array $b) {
+  return strnatcasecmp($a['name'], $b['name']);
+}
+
+/**
+ * Returns the library's provider.
+ *
+ * The provider can be a module, a theme, or an info file.
+ *
+ * @param array $library
+ *   A library information array.
+ *
+ * @return string
+ *   The provider.
+ */
+function libraries_admin_get_provider($library) {
+  $provider = '';
+
+  switch ($library['info type']) {
+    case 'module':
+    case 'theme':
+      $info = system_get_info($library['info type'], $library[$library['info type']]);
+      $provider = $info['name'];
+      break;
+
+    case 'info file':
+      $provider = basename($library['info file']);
+      break;
+  }
+
+  return $provider;
+}
+
+/**
+ * Returns the library's provider and provider type.
+ *
+ * The provider type is either 'module', 'theme', or 'info file'.
+ *
+ * @param array $library
+ *   A library information array.
+ *
+ * @return string
+ *   The provider and provider type.
+ */
+function libraries_admin_get_provider_with_type($library) {
+  $provider = libraries_admin_get_provider($library);
+  $provider_with_type = '';
+
+  // This switch could be avoided by using $library['info type'], but that would
+  // hinder properly translating these strings.
+  switch ($library['info type']) {
+    case 'module':
+      $provider_with_type = t('%module module', array('%module' => $provider));
+      break;
+
+    case 'theme':
+      $provider_with_type = t('%theme theme', array('%theme' => $provider));
+      break;
+
+    case 'info file':
+      $provider_with_type = t('%info-file info file', array('%info-file' => $provider));
+      break;
+  }
+
+  return $provider_with_type;
+}

+ 484 - 0
sites/all/modules/contrib/dev/libraries/libraries.api.php

@@ -0,0 +1,484 @@
+<?php
+
+/**
+ * @file
+ * Documents API functions for Libraries module.
+ */
+
+/**
+ * Return information about external libraries.
+ *
+ * @return
+ *   An associative array whose keys are internal names of libraries and whose
+ *   values are describing each library. Each key is the directory name below
+ *   the 'libraries' directory, in which the library may be found. Each value is
+ *   an associative array containing:
+ *   - name: The official, human-readable name of the library.
+ *   - vendor url: The URL of the homepage of the library.
+ *   - download url: The URL of a web page on which the library can be obtained.
+ *   - download file url: (optional) The URL where the latest version of the
+ *     library can be downloaded. In case such a static URL exists the library
+ *     can be downloaded automatically via Drush. Run
+ *     'drush help libraries-download' in the command-line for more information.
+ *   - path: (optional) A relative path from the directory of the library to the
+ *     actual library. Only required if the extracted download package contains
+ *     the actual library files in a sub-directory.
+ *   - library path: (optional) The absolute path to the library directory. This
+ *     should not be declared normally, as it is automatically detected, to
+ *     allow for multiple possible library locations. A valid use-case is an
+ *     external library, in which case the full URL to the library should be
+ *     specified here.
+ *   - version: (optional) The version of the library. This should not be
+ *     declared normally, as it is automatically detected (see 'version
+ *     callback' below) to allow for version changes of libraries without code
+ *     changes of implementing modules and to support different versions of a
+ *     library simultaneously (though only one version can be installed per
+ *     site). A valid use-case is an external library whose version cannot be
+ *     determined programmatically. Either 'version' or 'version callback' (or
+ *     'version arguments' in case libraries_get_version() is being used as a
+ *     version callback) must be declared.
+ *   - version callback: (optional) The name of a function that detects and
+ *     returns the full version string of the library. The first argument is
+ *     always $library, an array containing all library information as described
+ *     here. There are two ways to declare the version callback's additional
+ *     arguments, either as a single $options parameter or as multiple
+ *     parameters, which correspond to the two ways to specify the argument
+ *     values (see 'version arguments'). Defaults to libraries_get_version().
+ *     Unless 'version' is declared or libraries_get_version() is being used as
+ *     a version callback, 'version callback' must be declared. In the latter
+ *     case, however, 'version arguments' must be declared in the specified way.
+ *   - version arguments: (optional) A list of arguments to pass to the version
+ *     callback. Version arguments can be declared either as an associative
+ *     array whose keys are the argument names or as an indexed array without
+ *     specifying keys. If declared as an associative array, the arguments get
+ *     passed to the version callback as a single $options parameter whose keys
+ *     are the argument names (i.e. $options is identical to the specified
+ *     array). If declared as an indexed array, the array values get passed to
+ *     the version callback as separate arguments in the order they were
+ *     declared. The default version callback libraries_get_version() expects a
+ *     single, associative array with named keys:
+ *     - file: The filename to parse for the version, relative to the path
+ *       speficied as the 'library path' property (see above). For example:
+ *       'docs/changelog.txt'.
+ *     - pattern: A string containing a regular expression (PCRE) to match the
+ *       library version. For example: '@version\s+([0-9a-zA-Z\.-]+)@'. Note
+ *       that the returned version is not the match of the entire pattern (i.e.
+ *       '@version 1.2.3' in the above example) but the match of the first
+ *       sub-pattern (i.e. '1.2.3' in the above example).
+ *     - lines: (optional) The maximum number of lines to search the pattern in.
+ *       Defaults to 20.
+ *     - cols: (optional) The maximum number of characters per line to take into
+ *       account. Defaults to 200. In case of minified or compressed files, this
+ *       prevents reading the entire file into memory.
+ *     Defaults to an empty array. 'version arguments' must be specified unless
+ *     'version' is declared or the specified 'version callback' does not
+ *     require any arguments. The latter might be the case with a
+ *     library-specific version callback, for example.
+ *   - files: An associative array of library files to load. Supported keys are:
+ *     - js: A list of JavaScript files to load, using the same syntax as Drupal
+ *       core's hook_library().
+ *     - css: A list of CSS files to load, using the same syntax as Drupal
+ *       core's hook_library().
+ *     - php: A list of PHP files to load.
+ *   - dependencies: An array of libraries this library depends on. Similar to
+ *     declaring module dependencies, the dependency declaration may contain
+ *     information on the supported version. Examples of supported declarations:
+ *     @code
+ *     $libraries['dependencies'] = array(
+ *       // Load the 'example' library, regardless of the version available:
+ *       'example',
+ *       // Only load the 'example' library, if version 1.2 is available:
+ *       'example (1.2)',
+ *       // Only load a version later than 1.3-beta2 of the 'example' library:
+ *       'example (>1.3-beta2)'
+ *       // Only load a version equal to or later than 1.3-beta3:
+ *       'example (>=1.3-beta3)',
+ *       // Only load a version earlier than 1.5:
+ *       'example (<1.5)',
+ *       // Only load a version equal to or earlier than 1.4:
+ *       'example (<=1.4)',
+ *       // Combinations of the above are allowed as well:
+ *       'example (>=1.3-beta2, <1.5)',
+ *     );
+ *     @endcode
+ *   - variants: (optional) An associative array of available library variants.
+ *     For example, the top-level 'files' property may refer to a default
+ *     variant that is compressed. If the library also ships with a minified and
+ *     uncompressed/source variant, those can be defined here. Each key should
+ *     describe the variant type, e.g. 'minified' or 'source'. Each value is an
+ *     associative array of top-level properties that are entirely overridden by
+ *     the variant, most often just 'files'. Additionally, each variant can
+ *     contain following properties:
+ *     - variant callback: (optional) The name of a function that detects the
+ *       variant and returns TRUE or FALSE, depending on whether the variant is
+ *       available or not. The first argument is always $library, an array
+ *       containing all library information as described here. The second
+ *       argument is always a string containing the variant name. There are two
+ *       ways to declare the variant callback's additional arguments, either as a
+ *       single $options parameter or as multiple parameters, which correspond
+ *       to the two ways to specify the argument values (see 'variant
+ *       arguments'). If omitted, the variant is expected to always be
+ *       available.
+ *     - variant arguments: A list of arguments to pass to the variant callback.
+ *       Variant arguments can be declared either as an associative array whose
+ *       keys are the argument names or as an indexed array without specifying
+ *       keys. If declared as an associative array, the arguments get passed to
+ *       the variant callback as a single $options parameter whose keys are the
+ *       argument names (i.e. $options is identical to the specified array). If
+ *       declared as an indexed array, the array values get passed to the
+ *       variant callback as separate arguments in the order they were declared.
+ *     Variants can be version-specific (see 'versions').
+ *   - versions: (optional) An associative array of supported library versions.
+ *     Naturally, libraries evolve over time and so do their APIs. In case a
+ *     library changes between versions, different 'files' may need to be
+ *     loaded, different 'variants' may become available, or Drupal modules need
+ *     to load different integration files adapted to the new version. Each key
+ *     is a version *string* (PHP does not support floats as keys). Each value
+ *     is an associative array of top-level properties that are entirely
+ *     overridden by the version.
+ *   - integration files: (optional) An associative array whose keys are module
+ *     names and whose values are sets of files to load for the module, using
+ *     the same notion as the top-level 'files' property. Each specified file
+ *     should contain the path to the file relative to the module it belongs to.
+ *   - callbacks: An associative array whose keys are callback groups and whose
+ *     values are arrays of callbacks to apply to the library in that group.
+ *     Each callback receives the following arguments:
+ *     - $library: An array of library information belonging to the top-level
+ *       library, a specific version, a specific variant or a specific variant
+ *       of a specific version. Because library information such as the 'files'
+ *       property (see above) can be declared in all these different locations
+ *       of the library array, but a callback may have to act on all these
+ *       different parts of the library, it is called recursively for each
+ *       library with a certain part of the libraries array passed as $library
+ *       each time.
+ *     - $version: If the $library array belongs to a certain version (see
+ *       above), a string containing the version. This argument may be empty, so
+ *       NULL should be specified as the default value.
+ *     - $variant: If the $library array belongs to a certain variant (see
+ *       above), a string containing the variant name. This argument may be
+ *       empty, so NULL should be specified as the default value.
+ *     Valid callback groups are:
+ *     - info: Callbacks registered in this group are applied after the library
+ *       information has been retrieved via hook_libraries_info() or info files.
+ *       At this point the following additional information is available:
+ *       - $library['info type']: How the library information was obtained. Can
+ *         be 'info file', 'module', or 'theme', depending on whether the
+ *         library information was obtained from an info file, an enabled module
+ *         or an enabled theme, respectively.
+ *       Additionally, one of the following three keys is available, depending
+ *       on the value of $library['info type'].
+ *       - $library['info file']: In case the library information was obtained
+ *         from an info file, the URI of the info file.
+ *       - $library['module']: In case the library was obtained from an enabled
+ *         module, the name of the providing module.
+ *       - $library['theme']: In case the library was obtained from an enabled
+ *         theme, the name of the providing theme.
+ *     - pre-detect: Callbacks registered in this group are applied after the
+ *       library path has been determined and before the version callback is
+ *       invoked. At this point the following additional information is
+ *       available:
+ *       - $library['library path']: The path on the file system to the library.
+ *     - post-detect: Callbacks registered in this group are applied after the
+ *       library has been successfully detected. At this point the library
+ *       contains the version-specific information, if specified, and following
+ *       additional information is available:
+ *       - $library['installed']: A boolean indicating whether the library is
+ *         installed or not.
+ *       - $library['version']: If it could be detected, a string containing the
+ *         version of the library.
+ *       - $library['variants'][$variant]['installed']: For each specified
+ *         variant, a boolean indicating whether the variant is installed or
+ *         not.
+ *       Note that in this group the 'versions' property is no longer available.
+ *     - pre-dependencies-load: Callbacks registered in this group are applied
+ *       directly before the library's dependencies are loaded. At this point
+ *       the library contains variant-specific information, if specified. Note
+ *       that in this group the 'variants' property is no longer available.
+ *     - pre-load: Callbacks registered in this group are applied directly after
+ *       the library's dependencies are loaded and before the library itself is
+ *       loaded.
+ *     - post-load: Callbacks registered in this group are applied directly
+ *       after this library is loaded. At this point, the library contains a
+ *       'loaded' key, which contains the number of files that were loaded.
+ *   Additional top-level properties can be registered as needed.
+ *
+ * @see hook_library()
+ */
+function hook_libraries_info() {
+  // The following is a full explanation of all properties. See below for more
+  // concrete example implementations.
+
+  // This array key lets Libraries API search for 'sites/all/libraries/example'
+  // directory, which should contain the entire, original extracted library.
+  $libraries['example'] = array(
+    // Only used in administrative UI of Libraries API.
+    'name' => 'Example library',
+    'vendor url' => 'http://example.com',
+    'download url' => 'http://example.com/download',
+    // It is important that this URL does not include the actual version to
+    // download. Not all libraries provide such a static URL.
+    'download file url' => 'http://example.com/latest.tar.gz',
+    // Optional: If, after extraction, the actual library files are contained in
+    // 'sites/all/libraries/example/lib', specify the relative path here.
+    'path' => 'lib',
+    // Optional: Define a custom version detection callback, if required.
+    'version callback' => 'mymodule_get_version',
+    // Specify arguments for the version callback. By default,
+    // libraries_get_version() takes a named argument array:
+    'version arguments' => array(
+      'file' => 'docs/CHANGELOG.txt',
+      'pattern' => '@version\s+([0-9a-zA-Z\.-]+)@',
+      'lines' => 5,
+      'cols' => 20,
+    ),
+    // Default list of files of the library to load. Important: Only specify
+    // third-party files belonging to the library here, not integration files of
+    // your module.
+    'files' => array(
+      // 'js' and 'css' follow the syntax of hook_library(), but file paths are
+      // relative to the library path.
+      'js' => array(
+        'exlib.js',
+        'gadgets/foo.js',
+      ),
+      'css' => array(
+        'lib_style.css',
+        'skin/example.css',
+      ),
+      // For PHP libraries, specify include files here, still relative to the
+      // library path.
+      'php' => array(
+        'exlib.php',
+        'exlib.inc',
+      ),
+    ),
+    // Optional: Specify alternative variants of the library, if available.
+    'variants' => array(
+      // All properties defined for 'minified' override top-level properties.
+      'minified' => array(
+        'files' => array(
+          'js' => array(
+            'exlib.min.js',
+            'gadgets/foo.min.js',
+          ),
+          'css' => array(
+            'lib_style.css',
+            'skin/example.css',
+          ),
+        ),
+        'variant callback' => 'mymodule_check_variant',
+        'variant arguments' => array(
+          'variant' => 'minified',
+        ),
+      ),
+    ),
+    // Optional, but usually required: Override top-level properties for later
+    // versions of the library. The properties of the minimum version that is
+    // matched override the top-level properties. Note:
+    // - When registering 'versions', it usually does not make sense to register
+    //   'files', 'variants', and 'integration files' on the top-level, as most
+    //   of those likely need to be different per version and there are no
+    //   defaults.
+    // - The array keys have to be strings, as PHP does not support floats for
+    //   array keys.
+    'versions' => array(
+      '2' => array(
+        'files' => array(
+          'js' => array('exlib.js'),
+          'css' => array('exlib_style.css'),
+        ),
+      ),
+      '3.0' => array(
+        'files' => array(
+          'js' => array('exlib.js'),
+          'css' => array('lib_style.css'),
+        ),
+      ),
+      '3.2' => array(
+        'files' => array(
+          'js' => array(
+            'exlib.js',
+            'gadgets/foo.js',
+          ),
+          'css' => array(
+            'lib_style.css',
+            'skin/example.css',
+          ),
+        ),
+      ),
+    ),
+    // Optional: Register files to auto-load for your module. All files must be
+    // keyed by module, and follow the syntax of the 'files' property.
+    'integration files' => array(
+      'mymodule' => array(
+        'js' => array('ex_lib.inc'),
+      ),
+    ),
+    // Optionally register callbacks to apply to the library during different
+    // stages of its lifetime ('callback groups').
+    'callbacks' => array(
+      // Used to alter the info associated with the library.
+      'info' => array(
+        'mymodule_example_libraries_info_callback',
+      ),
+      // Called before detecting the given library.
+      'pre-detect' => array(
+        'mymodule_example_libraries_predetect_callback',
+      ),
+      // Called after detecting the library.
+      'post-detect' => array(
+        'mymodule_example_libraries_postdetect_callback',
+      ),
+      // Called before the library's dependencies are loaded.
+      'pre-dependencies-load' => array(
+        'mymodule_example_libraries_pre_dependencies_load_callback',
+      ),
+      // Called before the library is loaded.
+      'pre-load' => array(
+        'mymodule_example_libraries_preload_callback',
+      ),
+      // Called after the library is loaded.
+      'post-load' => array(
+        'mymodule_example_libraries_postload_callback',
+      ),
+    ),
+  );
+
+  // A very simple library. No changing APIs (hence, no versions), no variants.
+  // Expected to be extracted into 'sites/all/libraries/simple'.
+  $libraries['simple'] = array(
+    'name' => 'Simple library',
+    'vendor url' => 'http://example.com/simple',
+    'download url' => 'http://example.com/simple',
+    // The download file URL can also point to a single file (instead of an
+    // archive).
+    'download file url' => 'http://example.com/latest/simple.js',
+    'version arguments' => array(
+      'file' => 'readme.txt',
+      // Best practice: Document the actual version strings for later reference.
+      // 1.x: Version 1.0
+      'pattern' => '/Version (\d+)/',
+      'lines' => 5,
+    ),
+    'files' => array(
+      'js' => array('simple.js'),
+    ),
+  );
+
+  // A library that (naturally) evolves over time with API changes.
+  $libraries['tinymce'] = array(
+    'name' => 'TinyMCE',
+    'vendor url' => 'http://tinymce.moxiecode.com',
+    'download url' => 'http://tinymce.moxiecode.com/download.php',
+    'path' => 'jscripts/tiny_mce',
+    // The regular expression catches two parts (the major and the minor
+    // version), which libraries_get_version() doesn't allow.
+    'version callback' => 'tinymce_get_version',
+    'version arguments' => array(
+      // It can be easier to parse the first characters of a minified file
+      // instead of doing a multi-line pattern matching in a source file. See
+      // 'lines' and 'cols' below.
+      'file' => 'jscripts/tiny_mce/tiny_mce.js',
+      // Best practice: Document the actual version strings for later reference.
+      // 2.x: this.majorVersion="2";this.minorVersion="1.3"
+      // 3.x: majorVersion:'3',minorVersion:'2.0.1'
+      'pattern' => '@majorVersion[=:]["\'](\d).+?minorVersion[=:]["\']([\d\.]+)@',
+      'lines' => 1,
+      'cols' => 100,
+    ),
+    'versions' => array(
+      '2.1' => array(
+        'files' => array(
+          'js' => array('tiny_mce.js'),
+        ),
+        'variants' => array(
+          'source' => array(
+            'files' => array(
+              'js' => array('tiny_mce_src.js'),
+            ),
+          ),
+        ),
+        'integration files' => array(
+          'wysiwyg' => array(
+            'js' => array('editors/js/tinymce-2.js'),
+            'css' => array('editors/js/tinymce-2.css'),
+          ),
+        ),
+      ),
+      // Definition used if 3.1 or above is detected.
+      '3.1' => array(
+        // Does not support JS aggregation.
+        'files' => array(
+          'js' => array(
+            'tiny_mce.js' => array('preprocess' => FALSE),
+          ),
+        ),
+        'variants' => array(
+          // New variant leveraging jQuery. Not stable yet; therefore not the
+          // default variant.
+          'jquery' => array(
+            'files' => array(
+              'js' => array(
+                'tiny_mce_jquery.js' => array('preprocess' => FALSE),
+              ),
+            ),
+          ),
+          'source' => array(
+            'files' => array(
+              'js' => array(
+                'tiny_mce_src.js' => array('preprocess' => FALSE),
+              ),
+            ),
+          ),
+        ),
+        'integration files' => array(
+          'wysiwyg' => array(
+            'js' => array('editors/js/tinymce-3.js'),
+            'css' => array('editors/js/tinymce-3.css'),
+          ),
+        ),
+      ),
+    ),
+  );
+  return $libraries;
+}
+
+/**
+ * Alter the library information before detection and caching takes place.
+ *
+ * The library definitions are passed by reference. A common use-case is adding
+ * a module's integration files to the library array, so that the files are
+ * loaded whenever the library is. As noted above, it is important to declare
+ * integration files inside of an array, whose key is the module name.
+ *
+ * @see hook_libraries_info()
+ */
+function hook_libraries_info_alter(&$libraries) {
+  $files = array(
+    'php' => array('example_module.php_spellchecker.inc'),
+  );
+  $libraries['php_spellchecker']['integration files']['example_module'] = $files;
+}
+
+/**
+ * Specify paths to look for library info files.
+ *
+ * Libraries API looks in the following directories for library info files by
+ * default:
+ * - libraries
+ * - profiles/$profile/libraries
+ * - sites/all/libraries
+ * - sites/$site/libraries
+ * This hook allows you to specify additional locations to look for library info
+ * files. This should only be used for modules that declare many libraries.
+ * Modules that only implement a few libraries should implement
+ * hook_libraries_info().
+ *
+ * @return
+ *   An array of paths.
+ */
+function hook_libraries_info_file_paths() {
+  // Taken from the Libraries test module, which needs to specify the path to
+  // the test library.
+  return array(drupal_get_path('module', 'libraries_test') . '/example');
+}

+ 229 - 0
sites/all/modules/contrib/dev/libraries/libraries.drush.inc

@@ -0,0 +1,229 @@
+<?php
+/**
+ * @file
+ * Drush integration for Libraries API.
+ */
+
+/**
+ * Implements hook_drush_command().
+ */
+function libraries_drush_command() {
+  $items = array();
+
+  $items['libraries-list'] = array(
+    'description' => dt('Show a list of registered libraries.'),
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL,
+    'aliases' => array('lls', 'lib-list'),
+  );
+
+  $items['libraries-download'] = array(
+    'description' => dt('Download library files of registered libraries.'),
+    'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL,
+    'aliases' => array('ldl', 'lib-download'),
+    'arguments' => array(
+      'libraries' => 'A comma delimited list of library machine names.',
+    ),
+    'required-arguments' => TRUE,
+  );
+
+  return $items;
+}
+
+/**
+ * Implements hook_drush_cache_clear().
+ *
+ * @see drush_cache_clear_types()
+ */
+function libraries_drush_cache_clear(array &$types) {
+  $types['libraries'] = 'libraries_drush_invalidate_cache';
+}
+
+/**
+ * Clears the library cache.
+ */
+function libraries_drush_invalidate_cache() {
+  // @see drupal_flush_all_caches()
+  foreach (libraries_flush_caches() as $table) {
+    cache_clear_all('*', $table, TRUE);
+  }
+}
+
+/**
+ * Command callback. Show a list of registered libraries.
+ */
+function drush_libraries_list() {
+  $libraries = libraries_detect();
+  ksort($libraries);
+
+  if (empty($libraries)) {
+    drush_print('There are no registered libraries.');
+  }
+  else {
+    module_load_include('inc', 'libraries', 'libraries.admin');
+
+    $rows = array();
+    // drush_print_table() automatically treats the first row as the header, if
+    // $header is TRUE.
+    $rows[] = array(
+      dt('Name'),
+      dt('Status'),
+      dt('Version'),
+      dt('Variants'),
+      dt('Dependencies'),
+      dt('Provider'),
+    );
+    foreach ($libraries as $name => $library) {
+      // Only list installed variants.
+      $variants = array();
+      foreach ($library['variants'] as $variant_name => $variant) {
+        if ($variant['installed']) {
+          $variants[] = $variant_name;
+        }
+      }
+
+      $rows[] = array(
+        $name,
+        $library['installed'] ? dt('OK') : drupal_ucfirst($library['error']),
+        ($library['installed'] && $library['version']) ? '-' : $library['version'],
+        $variants ? implode(', ', $variants) : '-',
+        $library['dependencies'] ? implode(', ', $library['dependencies']) : '-',
+        libraries_admin_get_provider($library),
+      );
+    }
+
+    // Make the possible values for the 'Status' column and the 'Version' header
+    // wrap nicely.
+    $widths = array(0, 12, 7, 0, 0, 0);
+    drush_print_table($rows, TRUE, $widths);
+  }
+}
+
+/**
+ * Command callback. Downloads a library.
+ *
+ * Only libraries that provide a download file URL can be downloaded.
+ *
+ * @see hook_libraries_info()
+ * @see drush_pm_download()
+ */
+function drush_libraries_download() {
+  drush_command_include('pm-download');
+
+  $libraries = libraries_info();
+
+  // @todo Consider supporting downloading all downloadable libraries.
+  // @todo Consider offering a selection if no library is specified.
+  foreach (pm_parse_arguments(func_get_args(), FALSE) as $machine_name) {
+    if (!isset($libraries[$machine_name])) {
+      $message = dt("The !library library is not registered with Libraries API.\n", array('!library' => $machine_name));
+      $message .= dt("Provide an info file for it or implement hook_libraries_info().\n");
+      $message .= dt("See hook_libraries_info() for more information.\n");
+      drush_set_error('DRUSH_LIBRARY_UKNOWN', $message);
+      continue;
+    }
+    $library = $libraries[$machine_name];
+
+    if (empty($library['download file url'])) {
+      $message = dt("The !library library cannot be downloaded.\n", array('!library' => $machine_name));
+      $message .= dt("Libraries need to specify a download file URL to support being downloaded via Drush.\n");
+      $message .= dt("See hook_libraries_info() for more information.\n");
+      drush_set_error('DRUSH_LIBRARY_NOT_DOWNLOADABLE', $message);
+      continue;
+    }
+    $download_url = $library['download file url'];
+
+    drush_log(dt('Downloading library !name ...', array('!name' => $machine_name)));
+
+    // @see package_handler_download_project() in wget.inc
+    // It cannot be used directly because it will always try to extract the
+    // archive which fails when downloading a single file.
+    // @todo Modify upstream to be able to use
+    //   package_handler_download_project() directly.
+    // Prepare download path. On Windows file name cannot contain '?'.
+    // See http://drupal.org/node/1782444
+    $filename = str_replace('?', '_', basename($download_url));
+    $download_path = drush_tempdir() . '/' . $filename;
+
+    // Download the tarball.
+    // Never cache the downloaded file. The downloading relies on the fact that
+    // different versions of the library are available under the same URL as new
+    // versions are released.
+    $download_path = drush_download_file($download_url, $download_path, 0);
+    if ($download_path || drush_get_context('DRUSH_SIMULATE')) {
+      drush_log(dt('Downloading !filename was successful.', array('!filename' => $filename)));
+    }
+    else {
+      drush_set_error('DRUSH_PM_DOWNLOAD_FAILED', dt('Unable to download !project to !path from !url.', array('!project' => $machine_name, '!path' => $download_path, '!url' => $download_url)));
+      drush_log(dt('Error downloading !name', array('!name' => $machine_name)), 'error');
+      continue;
+    }
+
+    // @todo Suport MD5 file hashing.
+
+    // Extract the tarball in place and return the full path to the untarred directory.
+    $download_base = dirname($download_path);
+    if (drush_file_is_tarball($download_path)) {
+      if (!$tar_file_list = drush_tarball_extract($download_path, $download_base, TRUE)) {
+        // An error has been logged.
+        return FALSE;
+      }
+      $tar_directory = drush_trim_path($tar_file_list[0]);
+      $download_path = $download_base . '/' . $tar_directory;
+    }
+    else {
+      $download_path = $download_base;
+    }
+
+    // Determine the install location for the project.  User provided
+    // --destination has preference.
+    $destination = drush_get_option('destination');
+    if (!empty($destination)) {
+      if (!file_exists($destination)) {
+        drush_mkdir($destination);
+      }
+      $install_location = realpath($destination);
+    }
+    else {
+      /** @see _pm_download_destination_lookup() */
+      // _pm_download_destination_lookup() pluralizes the passed type by
+      // appending an s.
+      // This relies on the fact that there is no library named 'contrib'.
+      // @todo Request that this be turned into a proper API upstream.
+      $install_location = _pm_download_destination('librarie');
+    }
+
+    // @todo Consider invoking a hook similar to
+    //   hook_drush_pm_download_destination_alter().
+
+    // @todo Consider adding version-control support similar to pm-download.
+
+    $install_location .= '/' . $machine_name;
+
+    // Check if install location already exists.
+    if (is_dir($install_location)) {
+      if (drush_confirm(dt('Install location !location already exists. Do you want to overwrite it?', array('!location' => $install_location)))) {
+        drush_delete_dir($install_location, TRUE);
+      }
+      else {
+        drush_log(dt("Skip installation of !project to !dest.", array('!project' => $library['machine name'], '!dest' => $install_location)), 'warning');
+        continue;
+      }
+    }
+
+    // Copy the project to the install location.
+    if (drush_op('_drush_recursive_copy', $download_path, $install_location)) {
+      drush_log(dt("Library !project downloaded to !dest.", array('!project' => $machine_name, '!dest' => $install_location)), 'success');
+
+      // @todo Consider invoking a hook similar to
+      //   hook_drush_pm_post_download().
+
+      // @todo Support printing release notes.
+    }
+    else {
+      // We don't `return` here in order to proceed with downloading additional projects.
+      drush_set_error('DRUSH_PM_DOWNLOAD_FAILED', dt("Project !project could not be downloaded to !dest.", array('!project' => $machine_name, '!dest' => $install_location)));
+    }
+
+    // @todo Consider adding notify support.
+  }
+}

+ 16 - 0
sites/all/modules/contrib/dev/libraries/libraries.info

@@ -0,0 +1,16 @@
+name = Libraries
+description = Allows version-dependent and shared usage of external libraries.
+core = 7.x
+; We use hook_system_theme_info() which was added in Drupal 7.11
+dependencies[] = system (>=7.11)
+files[] = tests/LibrariesAdminWebTest.test
+files[] = tests/LibrariesLoadWebTest.test
+files[] = tests/LibrariesUnitTest.test
+files[] = tests/LibrariesWebTestBase.test
+
+; Information added by Drupal.org packaging script on 2016-05-12
+version = "7.x-2.3"
+core = "7.x"
+project = "libraries"
+datestamp = "1463077450"
+

+ 36 - 0
sites/all/modules/contrib/dev/libraries/libraries.install

@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * @file
+ * Install, uninstall, and update functions for libraries.module.
+ */
+
+/**
+ * Implements hook_schema().
+ */
+function libraries_schema() {
+  $schema['cache_libraries'] = drupal_get_schema_unprocessed('system', 'cache');
+  $schema['cache_libraries']['description'] = 'Cache table to store library information.';
+  return $schema;
+}
+
+/**
+ * Create the 'cache_libraries' table.
+ */
+function libraries_update_7200() {
+  // Note that previous versions of this function created the table with a
+  // different table comment.
+  if (!db_table_exists('cache_libraries')) {
+    $specs = libraries_schema();
+    db_create_table('cache_libraries', $specs['cache_libraries']);
+  }
+}
+
+/**
+ * Rebuild the class registry.
+ */
+function libraries_update_7201() {
+  // The tests were split from a single libraries.test file into multiple files
+  // during the 7.x-2.x cycle.
+  registry_rebuild();
+}

+ 946 - 0
sites/all/modules/contrib/dev/libraries/libraries.module

@@ -0,0 +1,946 @@
+<?php
+
+/**
+ * @file
+ * External library handling for Drupal modules.
+ */
+
+/**
+ * Implements hook_flush_caches().
+ */
+function libraries_flush_caches() {
+  // Clear static caches.
+  // We don't clear the 'libraries_load' static cache, because that could result
+  // in libraries that had been loaded before the cache flushing to be loaded
+  // again afterwards.
+  foreach (array('libraries_get_path', 'libraries_info') as $name) {
+    drupal_static_reset($name);
+  }
+
+  // @todo When upgrading from 1.x, update.php attempts to flush caches before
+  //   the cache table has been created.
+  // @see http://drupal.org/node/1477932
+  if (db_table_exists('cache_libraries')) {
+    return array('cache_libraries');
+  }
+}
+
+/**
+ * Gets the path of a library.
+ *
+ * @param $name
+ *   The machine name of a library to return the path for.
+ * @param $base_path
+ *   Whether to prefix the resulting path with base_path().
+ *
+ * @return string
+ *   The path to the specified library or FALSE if the library wasn't found.
+ *
+ * @ingroup libraries
+ */
+function libraries_get_path($name, $base_path = FALSE) {
+  $libraries = &drupal_static(__FUNCTION__);
+
+  if (!isset($libraries)) {
+    $libraries = libraries_get_libraries();
+  }
+
+  $path = ($base_path ? base_path() : '');
+  if (!isset($libraries[$name])) {
+    return FALSE;
+  }
+  else {
+    $path .= $libraries[$name];
+  }
+
+  return $path;
+}
+
+/**
+ * Returns an array of library directories.
+ *
+ * Returns an array of library directories from the all-sites directory
+ * (i.e. sites/all/libraries/), the profiles directory, and site-specific
+ * directory (i.e. sites/somesite/libraries/). The returned array will be keyed
+ * by the library name. Site-specific libraries are prioritized over libraries
+ * in the default directories. That is, if a library with the same name appears
+ * in both the site-wide directory and site-specific directory, only the
+ * site-specific version will be listed.
+ *
+ * @return array
+ *   A list of library directories.
+ *
+ * @ingroup libraries
+ */
+function libraries_get_libraries() {
+  $searchdir = array();
+  $profile = drupal_get_path('profile', drupal_get_profile());
+  $config = conf_path();
+
+  // Similar to 'modules' and 'themes' directories in the root directory,
+  // certain distributions may want to place libraries into a 'libraries'
+  // directory in Drupal's root directory.
+  $searchdir[] = 'libraries';
+
+  // Similar to 'modules' and 'themes' directories inside an installation
+  // profile, installation profiles may want to place libraries into a
+  // 'libraries' directory.
+  $searchdir[] = "$profile/libraries";
+
+  // Always search sites/all/libraries.
+  $searchdir[] = 'sites/all/libraries';
+
+  // Also search sites/<domain>/*.
+  $searchdir[] = "$config/libraries";
+
+  // Retrieve list of directories.
+  $directories = array();
+  $nomask = array('CVS');
+  foreach ($searchdir as $dir) {
+    if (is_dir($dir) && $handle = opendir($dir)) {
+      while (FALSE !== ($file = readdir($handle))) {
+        if (!in_array($file, $nomask) && $file[0] != '.') {
+          if (is_dir("$dir/$file")) {
+            $directories[$file] = "$dir/$file";
+          }
+        }
+      }
+      closedir($handle);
+    }
+  }
+
+  return $directories;
+}
+
+/**
+ * Looks for library info files.
+ *
+ * This function scans the following directories for info files:
+ * - libraries
+ * - profiles/$profilename/libraries
+ * - sites/all/libraries
+ * - sites/$sitename/libraries
+ * - any directories specified via hook_libraries_info_file_paths()
+ *
+ * @return array
+ *   An array of info files, keyed by library name. The values are the paths of
+ *   the files.
+ */
+function libraries_scan_info_files() {
+  $profile = drupal_get_path('profile', drupal_get_profile());
+  $config = conf_path();
+
+  // Build a list of directories.
+  $directories = module_invoke_all('libraries_info_file_paths');
+  $directories[] = 'libraries';
+  $directories[] = "$profile/libraries";
+  $directories[] = 'sites/all/libraries';
+  $directories[] = "$config/libraries";
+
+  // Scan for info files.
+  $files = array();
+  foreach ($directories as $dir) {
+    if (file_exists($dir)) {
+      $files = array_merge($files, file_scan_directory($dir, '@^[A-Za-z0-9._-]+\.libraries\.info$@', array(
+        'key' => 'name',
+        'recurse' => FALSE,
+      )));
+    }
+  }
+
+  foreach ($files as $filename => $file) {
+    $files[basename($filename, '.libraries')] = $file;
+    unset($files[$filename]);
+  }
+
+  return $files;
+}
+
+/**
+ * Invokes library callbacks.
+ *
+ * @param $group
+ *   A string containing the group of callbacks that is to be applied. Should be
+ *   either 'info', 'pre-detect', 'post-detect', or 'load'.
+ * @param $library
+ *   An array of library information, passed by reference.
+ */
+function libraries_invoke($group, &$library) {
+  // When introducing new callback groups in newer versions, stale cached
+  // library information somehow reaches this point during the database update
+  // before clearing the library cache.
+  if (empty($library['callbacks'][$group])) {
+    return;
+  }
+
+  foreach ($library['callbacks'][$group] as $callback) {
+    libraries_traverse_library($library, $callback);
+  }
+}
+
+/**
+ * Helper function to apply a callback to all parts of a library.
+ *
+ * Because library declarations can include variants and versions, and those
+ * version declarations can in turn include variants, modifying e.g. the 'files'
+ * property everywhere it is declared can be quite cumbersome, in which case
+ * this helper function is useful.
+ *
+ * @param $library
+ *   An array of library information, passed by reference.
+ * @param $callback
+ *   A string containing the callback to apply to all parts of a library.
+ */
+function libraries_traverse_library(&$library, $callback) {
+  // Always apply the callback to the top-level library.
+  $callback($library, NULL, NULL);
+
+  // Apply the callback to versions.
+  if (isset($library['versions'])) {
+    foreach ($library['versions'] as $version_string => &$version) {
+      $callback($version, $version_string, NULL);
+      // Versions can include variants as well.
+      if (isset($version['variants'])) {
+        foreach ($version['variants'] as $version_variant_name => &$version_variant) {
+          $callback($version_variant, $version_string, $version_variant_name);
+        }
+      }
+    }
+  }
+
+  // Apply the callback to variants.
+  if (isset($library['variants'])) {
+    foreach ($library['variants'] as $variant_name => &$variant) {
+      $callback($variant, NULL, $variant_name);
+    }
+  }
+}
+
+/**
+ * Library info callback to make all 'files' properties consistent.
+ *
+ * This turns libraries' file information declared as e.g.
+ * @code
+ * $library['files']['js'] = array('example_1.js', 'example_2.js');
+ * @endcode
+ * into
+ * @code
+ * $library['files']['js'] = array(
+ *   'example_1.js' => array(),
+ *   'example_2.js' => array(),
+ * );
+ * @endcode
+ * It does the same for the 'integration files' property.
+ *
+ * @param $library
+ *   An associative array of library information or a part of it, passed by
+ *   reference.
+ * @param $version
+ *   If the library information belongs to a specific version, the version
+ *   string. NULL otherwise.
+ * @param $variant
+ *   If the library information belongs to a specific variant, the variant name.
+ *   NULL otherwise.
+ *
+ * @see libraries_info()
+ * @see libraries_invoke()
+ */
+function libraries_prepare_files(&$library, $version = NULL, $variant = NULL) {
+  // Both the 'files' property and the 'integration files' property contain file
+  // declarations, and we want to make both consistent.
+  $file_types = array();
+  if (isset($library['files'])) {
+    $file_types[] = &$library['files'];
+  }
+  if (isset($library['integration files'])) {
+    // Integration files are additionally keyed by module.
+    foreach ($library['integration files'] as &$integration_files) {
+      $file_types[] = &$integration_files;
+    }
+  }
+  foreach ($file_types as &$files) {
+    // Go through all supported types of files.
+    foreach (array('js', 'css', 'php') as $type) {
+      if (isset($files[$type])) {
+        foreach ($files[$type] as $key => $value) {
+          // Unset numeric keys and turn the respective values into keys.
+          if (is_numeric($key)) {
+            $files[$type][$value] = array();
+            unset($files[$type][$key]);
+          }
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Library post-detect callback to process and detect dependencies.
+ *
+ * It checks whether each of the dependencies of a library are installed and
+ * available in a compatible version.
+ *
+ * @param $library
+ *   An associative array of library information or a part of it, passed by
+ *   reference.
+ * @param $version
+ *   If the library information belongs to a specific version, the version
+ *   string. NULL otherwise.
+ * @param $variant
+ *   If the library information belongs to a specific variant, the variant name.
+ *   NULL otherwise.
+ *
+ * @see libraries_info()
+ * @see libraries_invoke()
+ */
+function libraries_detect_dependencies(&$library, $version = NULL, $variant = NULL) {
+  if (isset($library['dependencies'])) {
+    foreach ($library['dependencies'] as &$dependency_string) {
+      $dependency_info = drupal_parse_dependency($dependency_string);
+      $dependency = libraries_detect($dependency_info['name']);
+      if (!$dependency['installed']) {
+        $library['installed'] = FALSE;
+        $library['error'] = 'missing dependency';
+        $library['error message'] = t('The %dependency library, which the %library library depends on, is not installed.', array(
+          '%dependency' => $dependency['name'],
+          '%library' => $library['name'],
+        ));
+      }
+      elseif (drupal_check_incompatibility($dependency_info, $dependency['version'])) {
+        $library['installed'] = FALSE;
+        $library['error'] = 'incompatible dependency';
+        $library['error message'] = t('The version %dependency_version of the %dependency library is not compatible with the %library library.', array(
+          '%dependency_version' => $dependency['version'],
+          '%dependency' => $dependency['name'],
+          '%library' => $library['name'],
+        ));
+      }
+
+      // Remove the version string from the dependency, so libraries_load() can
+      // load the libraries directly.
+      $dependency_string = $dependency_info['name'];
+    }
+  }
+}
+
+/**
+ * Returns information about registered libraries.
+ *
+ * The returned information is unprocessed; i.e., as registered by modules.
+ *
+ * @param $name
+ *   (optional) The machine name of a library to return registered information
+ *   for. If omitted, information about all registered libraries is returned.
+ *
+ * @return array|false
+ *   An associative array containing registered information for all libraries,
+ *   the registered information for the library specified by $name, or FALSE if
+ *   the library $name is not registered.
+ *
+ * @see hook_libraries_info()
+ *
+ * @todo Re-introduce support for include file plugin system - either by copying
+ *   Wysiwyg's code, or directly switching to CTools.
+ */
+function &libraries_info($name = NULL) {
+  // This static cache is re-used by libraries_detect() to save memory.
+  $libraries = &drupal_static(__FUNCTION__);
+
+  if (!isset($libraries)) {
+    $libraries = array();
+
+    // Gather information from hook_libraries_info() in enabled modules.
+    foreach (module_implements('libraries_info') as $module) {
+      foreach (module_invoke($module, 'libraries_info') as $machine_name => $properties) {
+        $properties['info type'] = 'module';
+        $properties['module'] = $module;
+        $libraries[$machine_name] = $properties;
+      }
+    }
+
+    // Gather information from hook_libraries_info() in enabled themes.
+    $themes = array();
+    foreach (list_themes() as $theme_name => $theme_info) {
+      if ($theme_info->status && file_exists(drupal_get_path('theme', $theme_name) . '/template.php')) {
+        // Collect a list of viable themes for re-use when calling the alter
+        // hook.
+        $themes[] = $theme_name;
+
+        include_once drupal_get_path('theme', $theme_name) . '/template.php';
+
+        $function = $theme_name . '_libraries_info';
+        if (function_exists($function)) {
+          foreach ($function() as $machine_name => $properties) {
+            $properties['info type'] = 'theme';
+            $properties['theme'] = $theme_name;
+            $libraries[$machine_name] = $properties;
+          }
+        }
+      }
+    }
+
+    // Gather information from .info files.
+    // .info files override module definitions.
+    foreach (libraries_scan_info_files() as $machine_name => $file) {
+      $properties = drupal_parse_info_file($file->uri);
+      $properties['info type'] = 'info file';
+      $properties['info file'] = $file->uri;
+      $libraries[$machine_name] = $properties;
+    }
+
+    // Provide defaults.
+    foreach ($libraries as $machine_name => &$properties) {
+      libraries_info_defaults($properties, $machine_name);
+    }
+
+    // Allow enabled modules and themes to alter the registered libraries.
+    // drupal_alter() only takes the currently active theme into account, not
+    // all enabled themes.
+    foreach (module_implements('libraries_info_alter') as $module) {
+      $function = $module . '_libraries_info_alter';
+      $function($libraries);
+    }
+    foreach ($themes as $theme) {
+      $function = $theme . '_libraries_info_alter';
+      // The template.php file was included above.
+      if (function_exists($function)) {
+        $function($libraries);
+      }
+    }
+
+    // Invoke callbacks in the 'info' group.
+    foreach ($libraries as &$properties) {
+      libraries_invoke('info', $properties);
+    }
+  }
+
+  if (isset($name)) {
+    if (!empty($libraries[$name])) {
+      return $libraries[$name];
+    }
+    else {
+      $false = FALSE;
+      return $false;
+    }
+  }
+  return $libraries;
+}
+
+/**
+ * Applies default properties to a library definition.
+ *
+ * @param array $library
+ *   An array of library information, passed by reference.
+ * @param string $name
+ *   The machine name of the passed-in library.
+ *
+ * @return array
+ *   The library information array with defaults populated.
+ */
+function libraries_info_defaults(array &$library, $name) {
+  $library += array(
+    'machine name' => $name,
+    'name' => $name,
+    'vendor url' => '',
+    'download url' => '',
+    'download file url' => '',
+    'path' => '',
+    'library path' => NULL,
+    'version callback' => 'libraries_get_version',
+    'version arguments' => array(),
+    'files' => array(),
+    'dependencies' => array(),
+    'variants' => array(),
+    'versions' => array(),
+    'integration files' => array(),
+    'callbacks' => array(),
+    // @todo Remove in 7.x-3.x
+    'post-load integration files' => FALSE,
+  );
+  $library['callbacks'] += array(
+    'info' => array(),
+    'pre-detect' => array(),
+    'post-detect' => array(),
+    'pre-dependencies-load' => array(),
+    'pre-load' => array(),
+    'post-load' => array(),
+  );
+
+  // Add our own callbacks before any others.
+  array_unshift($library['callbacks']['info'], 'libraries_prepare_files');
+  array_unshift($library['callbacks']['post-detect'], 'libraries_detect_dependencies');
+
+  return $library;
+}
+
+/**
+ * Tries to detect a library and its installed version.
+ *
+ * @param string $name
+ *   (optional) The machine name of a library to detect and return registered
+ *   information for. If omitted, information about all registered libraries is
+ *   returned.
+ *
+ * @return array|false
+ *   An associative array containing registered information for all libraries,
+ *   the registered information for the library specified by $name, or FALSE if
+ *   the library $name is not registered.
+ *   In addition to the keys returned by libraries_info(), the following keys
+ *   are contained:
+ *   - installed: A boolean indicating whether the library is installed. Note
+ *     that not only the top-level library, but also each variant contains this
+ *     key.
+ *   - version: If the version could be detected, the full version string.
+ *   - error: If an error occurred during library detection, one of the
+ *     following error statuses: "not found", "not detected", "not supported".
+ *   - error message: If an error occurred during library detection, a detailed
+ *     error message.
+ *
+ * @see libraries_info()
+ */
+function libraries_detect($name = NULL) {
+  if (!isset($name)) {
+    $libraries = &libraries_info();
+    foreach ($libraries as $name => $library) {
+      libraries_detect($name);
+    }
+    return $libraries;
+  }
+
+  // Re-use the statically cached value of libraries_info() to save memory.
+  $library = &libraries_info($name);
+
+  // Exit early if the library was not found.
+  if ($library === FALSE) {
+    return $library;
+  }
+
+  // If 'installed' is set, library detection ran already.
+  if (isset($library['installed'])) {
+    return $library;
+  }
+
+  $library['installed'] = FALSE;
+
+  // Check whether the library exists.
+  if (!isset($library['library path'])) {
+    $library['library path'] = libraries_get_path($library['machine name']);
+  }
+  if ($library['library path'] === FALSE || !file_exists($library['library path'])) {
+    $library['error'] = 'not found';
+    $library['error message'] = t('The %library library could not be found.', array(
+      '%library' => $library['name'],
+    ));
+    return $library;
+  }
+
+  // Invoke callbacks in the 'pre-detect' group.
+  libraries_invoke('pre-detect', $library);
+
+  // Detect library version, if not hardcoded.
+  if (!isset($library['version'])) {
+    // We support both a single parameter, which is an associative array, and an
+    // indexed array of multiple parameters.
+    if (isset($library['version arguments'][0])) {
+      // Add the library as the first argument.
+      $library['version'] = call_user_func_array($library['version callback'], array_merge(array($library), $library['version arguments']));
+    }
+    else {
+      $library['version'] = call_user_func($library['version callback'], $library, $library['version arguments']);
+    }
+    if (empty($library['version'])) {
+      $library['error'] = 'not detected';
+      $library['error message'] = t('The version of the %library library could not be detected.', array(
+        '%library' => $library['name'],
+      ));
+      return $library;
+    }
+  }
+
+  // Determine to which supported version the installed version maps.
+  if (!empty($library['versions'])) {
+    ksort($library['versions']);
+    $version = 0;
+    foreach ($library['versions'] as $supported_version => $version_properties) {
+      if (version_compare($library['version'], $supported_version, '>=')) {
+        $version = $supported_version;
+      }
+    }
+    if (!$version) {
+      $library['error'] = 'not supported';
+      $library['error message'] = t('The installed version %version of the %library library is not supported.', array(
+        '%version' => $library['version'],
+        '%library' => $library['name'],
+      ));
+      return $library;
+    }
+
+    // Apply version specific definitions and overrides.
+    $library = array_merge($library, $library['versions'][$version]);
+    unset($library['versions']);
+  }
+
+  // Check each variant if it is installed.
+  if (!empty($library['variants'])) {
+    foreach ($library['variants'] as $variant_name => &$variant) {
+      // If no variant callback has been set, assume the variant to be
+      // installed.
+      if (!isset($variant['variant callback'])) {
+        $variant['installed'] = TRUE;
+      }
+      else {
+        // We support both a single parameter, which is an associative array,
+        // and an indexed array of multiple parameters.
+        if (isset($variant['variant arguments'][0])) {
+          // Add the library as the first argument, and the variant name as the second.
+          $variant['installed'] = call_user_func_array($variant['variant callback'], array_merge(array($library, $variant_name), $variant['variant arguments']));
+        }
+        else {
+          $variant['installed'] = $variant['variant callback']($library, $variant_name, $variant['variant arguments']);
+        }
+        if (!$variant['installed']) {
+          $variant['error'] = 'not found';
+          $variant['error message'] = t('The %variant variant of the %library library could not be found.', array(
+            '%variant' => $variant_name,
+            '%library' => $library['name'],
+          ));
+        }
+      }
+    }
+  }
+
+  // If we end up here, the library should be usable.
+  $library['installed'] = TRUE;
+
+  // Invoke callbacks in the 'post-detect' group.
+  libraries_invoke('post-detect', $library);
+
+  return $library;
+}
+
+/**
+ * Loads a library.
+ *
+ * @param $name
+ *   The name of the library to load.
+ * @param $variant
+ *   The name of the variant to load. Note that only one variant of a library
+ *   can be loaded within a single request. The variant that has been passed
+ *   first is used; different variant names in subsequent calls are ignored.
+ *
+ * @return
+ *   An associative array of the library information as returned from
+ *   libraries_info(). The top-level properties contain the effective definition
+ *   of the library (variant) that has been loaded. Additionally:
+ *   - installed: Whether the library is installed, as determined by
+ *     libraries_detect_library().
+ *   - loaded: Either the amount of library files that have been loaded, or
+ *     FALSE if the library could not be loaded.
+ *   See hook_libraries_info() for more information.
+ */
+function libraries_load($name, $variant = NULL) {
+  $loaded = &drupal_static(__FUNCTION__, array());
+
+  if (!isset($loaded[$name])) {
+    $library = cache_get($name, 'cache_libraries');
+    if ($library) {
+      $library = $library->data;
+    }
+    else {
+      $library = libraries_detect($name);
+      cache_set($name, $library, 'cache_libraries');
+    }
+
+    // Exit early if the library was not found.
+    if ($library === FALSE) {
+      $loaded[$name] = $library;
+      return $loaded[$name];
+    }
+
+    // If a variant was specified, override the top-level properties with the
+    // variant properties.
+    if (isset($variant)) {
+      // Ensure that the $variant key exists, and if it does not, set its
+      // 'installed' property to FALSE by default. This will prevent the loading
+      // of the library files below.
+      $library['variants'] += array($variant => array('installed' => FALSE));
+      $library = array_merge($library, $library['variants'][$variant]);
+    }
+    // Regardless of whether a specific variant was requested or not, there can
+    // only be one variant of a library within a single request.
+    unset($library['variants']);
+
+    // Invoke callbacks in the 'pre-dependencies-load' group.
+    libraries_invoke('pre-dependencies-load', $library);
+
+    // If the library (variant) is installed, load it.
+    $library['loaded'] = FALSE;
+    if ($library['installed']) {
+      // Load library dependencies.
+      if (isset($library['dependencies'])) {
+        foreach ($library['dependencies'] as $dependency) {
+          libraries_load($dependency);
+        }
+      }
+
+      // Invoke callbacks in the 'pre-load' group.
+      libraries_invoke('pre-load', $library);
+
+      // Load all the files associated with the library.
+      $library['loaded'] = libraries_load_files($library);
+
+      // Invoke callbacks in the 'post-load' group.
+      libraries_invoke('post-load', $library);
+    }
+    $loaded[$name] = $library;
+  }
+
+  return $loaded[$name];
+}
+
+/**
+ * Loads a library's files.
+ *
+ * @param $library
+ *   An array of library information as returned by libraries_info().
+ *
+ * @return
+ *   The number of loaded files.
+ */
+function libraries_load_files($library) {
+  // As this key was added after 7.x-2.1 cached library structures might not
+  // have it.
+  $library += array('post-load integration files' => FALSE);
+
+  // Load integration files.
+  if (!$library['post-load integration files'] && !empty($library['integration files'])) {
+    $enabled_themes = array();
+    foreach (list_themes() as $theme_name => $theme) {
+      if ($theme->status) {
+        $enabled_themes[] = $theme_name;
+      }
+    }
+    foreach ($library['integration files'] as $provider => $files) {
+      if (module_exists($provider)) {
+        libraries_load_files(array(
+          'files' => $files,
+          'path' => '',
+          'library path' => drupal_get_path('module', $provider),
+          'post-load integration files' => FALSE,
+        ));
+      }
+      elseif (in_array($provider, $enabled_themes)) {
+        libraries_load_files(array(
+          'files' => $files,
+          'path' => '',
+          'library path' => drupal_get_path('theme', $provider),
+          'post-load integration files' => FALSE,
+        ));
+      }
+    }
+  }
+
+  // Construct the full path to the library for later use.
+  $path = $library['library path'];
+  $path = ($library['path'] !== '' ? $path . '/' . $library['path'] : $path);
+
+  // Count the number of loaded files for the return value.
+  $count = 0;
+
+  // Load both the JavaScript and the CSS files.
+  // The parameters for drupal_add_js() and drupal_add_css() require special
+  // handling.
+  // @see drupal_process_attached()
+  foreach (array('js', 'css') as $type) {
+    if (!empty($library['files'][$type])) {
+      foreach ($library['files'][$type] as $data => $options) {
+        // If the value is not an array, it's a filename and passed as first
+        // (and only) argument.
+        if (!is_array($options)) {
+          $data = $options;
+          $options = array();
+        }
+        // In some cases, the first parameter ($data) is an array. Arrays can't
+        // be passed as keys in PHP, so we have to get $data from the value
+        // array.
+        if (is_numeric($data)) {
+          $data = $options['data'];
+          unset($options['data']);
+        }
+        // Prepend the library path to the file name.
+        $data = "$path/$data";
+        // Apply the default group if the group isn't explicitly given.
+        if (!isset($options['group'])) {
+          $options['group'] = ($type == 'js') ? JS_DEFAULT : CSS_DEFAULT;
+        }
+        call_user_func('drupal_add_' . $type, $data, $options);
+        $count++;
+      }
+    }
+  }
+
+  // Load PHP files.
+  if (!empty($library['files']['php'])) {
+    foreach ($library['files']['php'] as $file => $array) {
+      $file_path = DRUPAL_ROOT . '/' . $path . '/' . $file;
+      if (file_exists($file_path)) {
+        _libraries_require_once($file_path);
+        $count++;
+      }
+    }
+  }
+
+  // Load integration files.
+  if ($library['post-load integration files'] && !empty($library['integration files'])) {
+    $enabled_themes = array();
+    foreach (list_themes() as $theme_name => $theme) {
+      if ($theme->status) {
+        $enabled_themes[] = $theme_name;
+      }
+    }
+    foreach ($library['integration files'] as $provider => $files) {
+      if (module_exists($provider)) {
+        libraries_load_files(array(
+          'files' => $files,
+          'path' => '',
+          'library path' => drupal_get_path('module', $provider),
+          'post-load integration files' => FALSE,
+        ));
+      }
+      elseif (in_array($provider, $enabled_themes)) {
+        libraries_load_files(array(
+          'files' => $files,
+          'path' => '',
+          'library path' => drupal_get_path('theme', $provider),
+          'post-load integration files' => FALSE,
+        ));
+      }
+    }
+  }
+
+  return $count;
+}
+
+/**
+ * Wrapper function for require_once.
+ *
+ * A library file could set a $path variable in file scope. Requiring such a
+ * file directly in libraries_load_files() would lead to the local $path
+ * variable being overridden after the require_once statement. This would
+ * break loading further files. Therefore we use this trivial wrapper which has
+ * no local state that can be tampered with.
+ *
+ * @param $file_path
+ *   The file path of the file to require.
+ */
+function _libraries_require_once($file_path) {
+  require_once $file_path;
+}
+
+
+/**
+ * Gets the version information from an arbitrary library.
+ *
+ * @param $library
+ *   An associative array containing all information about the library.
+ * @param $options
+ *   An associative array containing with the following keys:
+ *   - file: The filename to parse for the version, relative to the library
+ *     path. For example: 'docs/changelog.txt'.
+ *   - pattern: A string containing a regular expression (PCRE) to match the
+ *     library version. For example: '@version\s+([0-9a-zA-Z\.-]+)@'. Note that
+ *     the returned version is not the match of the entire pattern (i.e.
+ *     '@version 1.2.3' in the above example) but the match of the first
+ *     sub-pattern (i.e. '1.2.3' in the above example).
+ *   - lines: (optional) The maximum number of lines to search the pattern in.
+ *     Defaults to 20.
+ *   - cols: (optional) The maximum number of characters per line to take into
+ *     account. Defaults to 200. In case of minified or compressed files, this
+ *     prevents reading the entire file into memory.
+ *
+ * @return
+ *   A string containing the version of the library.
+ *
+ * @see libraries_get_path()
+ */
+function libraries_get_version($library, $options) {
+  // Provide defaults.
+  $options += array(
+    'file' => '',
+    'pattern' => '',
+    'lines' => 20,
+    'cols' => 200,
+  );
+
+  $file = DRUPAL_ROOT . '/' . $library['library path'] . '/' . $options['file'];
+  if (empty($options['file']) || !file_exists($file)) {
+    return;
+  }
+  $file = fopen($file, 'r');
+  while ($options['lines'] && $line = fgets($file, $options['cols'])) {
+    if (preg_match($options['pattern'], $line, $version)) {
+      fclose($file);
+      return $version[1];
+    }
+    $options['lines']--;
+  }
+  fclose($file);
+}
+
+/**
+ * Implements hook_help().
+ */
+function libraries_help($path, $arg) {
+  switch ($path) {
+    case 'admin/reports/libraries':
+      return t('Click on a library for a status report or detailed installation instructions in case the library is not installed correctly.');
+  }
+}
+
+/**
+ * Implements hook_menu().
+ */
+function libraries_menu() {
+  $items = array();
+  $items['admin/reports/libraries'] = array(
+    'title' => 'Libraries',
+    'description' => 'An overview of libraries installed on this site.',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('libraries_admin_overview'),
+    'access arguments' => array('access site reports'),
+    'file' => 'libraries.admin.inc'
+  );
+  $items['admin/reports/libraries/%libraries_ui'] = array(
+    'title' => 'Library status report',
+    'description' => 'Status overview for a single library',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('libraries_admin_library_status_form', 3),
+    'access arguments' => array('access site reports'),
+    'file' => 'libraries.admin.inc'
+  );
+  return $items;
+}
+
+/**
+ * Loads library information for display in the user interface.
+ *
+ * This can be used as a menu loader function by specifying a '%libraries_ui'
+ * parameter in a path.
+ *
+ * We do not use libraries_load() (and, thus, a '%libraries' parameter) directly
+ * for displaying library information in the user interface as we do not want
+ * the library files to be loaded.
+ *
+ * @param string $name
+ *   The machine name of a library to return registered information for.
+ *
+ * @return array|false
+ *   An associative array containing registered information for the library
+ *   specified by $name, or FALSE if the library $name is not registered.
+ *
+ * @see libraries_detect()
+ * @see libraries_menu()
+ */
+function libraries_ui_load($name) {
+  return libraries_detect($name);
+}

+ 119 - 0
sites/all/modules/contrib/dev/libraries/tests/LibrariesAdminWebTest.test

@@ -0,0 +1,119 @@
+<?php
+
+/**
+ * @file
+ * Contains LibrariesAdminWebTest.
+ *
+ * Simpletest automatically discovers test files using PSR-4. We cannot,
+ * however, declare a namespace for this class, as that would require PHP 5.3.
+ * To prepare the PHP 5.3 requirement and the usage of PSR-4 in 7.x-3.x, we
+ * split each test class into its own file and use the correct base name, but
+ * for now use the 'test' extension and register them explicitly in
+ * libraries.info.
+ *
+ * @see simpletest_test_get_all()
+ */
+
+/**
+ * Tests the administrative interface for libraries.
+ */
+class LibrariesAdminWebTest extends LibrariesWebTestBase {
+
+  /**
+   * Provides metadata about this test.
+   *
+   * @return array
+   *   An array of test metadata with the following keys:
+   *   - name: The name of the test.
+   *   - description: The description of the test.
+   *   - group: The group of the test.
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Libraries administration',
+      'description' => 'Tests the administrative interface for libraries.',
+      'group' => 'Libraries API',
+    );
+  }
+
+  /**
+   * Tests the libraries report at /admin/reports/libraries.
+   */
+  public function testLibrariesReportOverview() {
+    $this->getWithPermissions(array('access site reports'), 'admin/reports/libraries');
+    $this->assertRaw('Libraries');
+
+    // Make sure that all the libraries are listed.
+    $libraries = libraries_info();
+    $this->assertTrue($libraries);
+    foreach ($libraries as $library) {
+      $this->assertText($library['name']);
+      $this->assertLinkByHref('admin/reports/libraries/' . $library['machine name']);
+    }
+
+    // Make sure that all possible statuses are displayed.
+    $this->assertText('OK');
+    $this->assertText('Not found');
+    $this->assertText('Not detected');
+    $this->assertText('Not supported');
+    $this->assertText('Missing dependency');
+    $this->assertText('Incompatible dependency');
+
+    // Make sure that the providers are displayed.
+    $this->assertRaw('<em class="placeholder">Libraries test module</em> module');
+    $this->assertRaw('<em class="placeholder">Libraries test theme</em> theme');
+    $this->assertRaw('<em class="placeholder">example_info_file.libraries.info</em> info file');
+
+    // Make sure that homepage and download links are displayed.
+    $this->assertLinkByHref('http://example.com');
+    $this->assertLinkByHref('http://example.com/download');
+  }
+
+  /**
+   * Tests the libraries report for an installed library.
+   */
+  public function testLibrariesReportInstalled() {
+    $this->getWithPermissions(array('access site reports'), 'admin/reports/libraries/example_files');
+    $this->assertRaw('Status report for library <em class="placeholder">Example files</em>');
+    $this->assertRaw('The <em class="placeholder">Example files</em> library is installed correctly.');
+    // Check that the information in the status report is displayed.
+    $this->assertText('Example files');
+    $this->assertText('example_files');
+    $this->assertRaw('<em class="placeholder">Libraries test module</em> module');
+    $this->assertText(drupal_get_path('module', 'libraries') . '/tests/libraries/example');
+    $this->assertText('1');
+  }
+
+  /**
+   * Tests the libraries report for a missing library.
+   */
+  public function testLibrariesReportMissing() {
+    $this->getWithPermissions(array('access site reports'), 'admin/reports/libraries/example_missing');
+    $this->assertRaw('Status report for library <em class="placeholder">Example missing</em>');
+    $this->assertRaw('The <em class="placeholder">Example missing</em> library could not be found.');
+    // Check that the download link is being displayed.
+    $this->assertLinkByHref('http://example.com/download');
+  }
+
+
+  /**
+   * Tests the libraries report for a missing library.
+   */
+  public function testLibrariesReportNotDetected() {
+    $this->getWithPermissions(array('access site reports'), 'admin/reports/libraries/example_undetected_version');
+    $this->assertRaw('Status report for library <em class="placeholder">Example undetected version</em>');
+    $this->assertRaw('The version of the <em class="placeholder">Example undetected version</em> library could not be detected.');
+  }
+
+  /**
+   * Tests the libraries report for a missing library.
+   */
+  public function testLibrariesReportNotSupported() {
+    $this->getWithPermissions(array('access site reports'), 'admin/reports/libraries/example_unsupported_version');
+    $this->assertRaw('Status report for library <em class="placeholder">Example unsupported version</em>');
+    $this->assertRaw('The installed version <em class="placeholder">1</em> of the <em class="placeholder">Example unsupported version</em> library is not supported.');
+    // Check that the download link is being displayed.
+    $this->assertLinkByHref('http://example.com/download');
+  }
+
+}

+ 543 - 0
sites/all/modules/contrib/dev/libraries/tests/LibrariesLoadWebTest.test

@@ -0,0 +1,543 @@
+<?php
+
+/**
+ * @file
+ * Contains LibrariesLoadWebTest.
+ *
+ * Simpletest automatically discovers test files using PSR-4. We cannot,
+ * however, declare a namespace for this class, as that would require PHP 5.3.
+ * To prepare the PHP 5.3 requirement and the usage of PSR-4 in 7.x-3.x, we
+ * place the test files in the correct directory already, but for now register
+ * them explicitly in libraries.info
+ */
+
+/**
+ * Tests basic detection and loading of libraries.
+ */
+class LibrariesLoadWebTest extends LibrariesWebTestBase {
+
+  /**
+   * Provides metadata about this test.
+   *
+   * @return array
+   *   An array of test metadata with the following keys:
+   *   - name: The name of the test.
+   *   - description: The description of the test.
+   *   - group: The group of the test.
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Libraries detection and loading',
+      'description' => 'Tests detection and loading of libraries.',
+      'group' => 'Libraries API',
+    );
+  }
+
+  /**
+   * Tests libraries_detect_dependencies().
+   */
+  public function testLibrariesDetectDependencies() {
+    $library = array(
+      'name' => 'Example',
+      'dependencies' => array('example_missing'),
+    );
+    libraries_detect_dependencies($library);
+    $this->assertEqual($library['error'], 'missing dependency', 'libraries_detect_dependencies() detects missing dependency');
+    $error_message = t('The %dependency library, which the %library library depends on, is not installed.', array(
+      '%dependency' => 'Example missing',
+      '%library' => $library['name'],
+    ));
+    $this->verbose("Expected:<br>$error_message");
+    $this->verbose('Actual:<br>' . $library['error message']);
+    $this->assertEqual($library['error message'], $error_message, 'Correct error message for a missing dependency');
+    // Test versioned dependencies.
+    $version = '1.1';
+    $compatible = array(
+      '1.1',
+      '<=1.1',
+      '>=1.1',
+      '<1.2',
+      '<2.0',
+      '>1.0',
+      '>1.0-rc1',
+      '>1.0-beta2',
+      '>1.0-alpha3',
+      '>0.1',
+      '<1.2, >1.0',
+      '>0.1, <=1.1',
+    );
+    $incompatible = array(
+      '1.2',
+      '2.0',
+      '<1.1',
+      '>1.1',
+      '<=1.0',
+      '<=1.0-rc1',
+      '<=1.0-beta2',
+      '<=1.0-alpha3',
+      '>=1.2',
+      '<1.1, >0.9',
+      '>=0.1, <1.1',
+    );
+    $library = array(
+      'name' => 'Example',
+    );
+    foreach ($compatible as $version_string) {
+      $library['dependencies'][0] = "example_dependency ($version_string)";
+      // libraries_detect_dependencies() is a post-detect callback, so
+      // 'installed' is already set, when it is called. It sets the value to
+      // FALSE for missing or incompatible dependencies.
+      $library['installed'] = TRUE;
+      libraries_detect_dependencies($library);
+      $this->verbose('Library:<pre>' . var_export($library, TRUE) . '</pre>');
+      $this->assertTrue($library['installed'], "libraries_detect_dependencies() detects compatible version string: '$version_string' is compatible with '$version'");
+    }
+    foreach ($incompatible as $version_string) {
+      $library['dependencies'][0] = "example_dependency ($version_string)";
+      $library['installed'] = TRUE;
+      unset($library['error'], $library['error message']);
+      libraries_detect_dependencies($library);
+      $this->verbose('Library:<pre>' . var_export($library, TRUE) . '</pre>');
+      $this->assertEqual($library['error'], 'incompatible dependency', "libraries_detect_dependencies() detects incompatible version strings: '$version_string' is incompatible with '$version'");
+    }
+    // Instead of repeating this assertion for each version string, we just
+    // re-use the $library variable from the foreach loop.
+    $error_message = t('The version %dependency_version of the %dependency library is not compatible with the %library library.', array(
+      '%dependency_version' => $version,
+      '%dependency' => 'Example dependency',
+      '%library' => $library['name'],
+    ));
+    $this->verbose("Expected:<br>$error_message");
+    $this->verbose('Actual:<br>' . $library['error message']);
+    $this->assertEqual($library['error message'], $error_message, 'Correct error message for an incompatible dependency');
+  }
+
+  /**
+   * Tests libraries_scan_info_files().
+   */
+  public function testLibrariesScanInfoFiles() {
+    $expected = array('example_info_file' => (object) array(
+      'uri' => drupal_get_path('module', 'libraries') . '/tests/libraries/example_info_file.libraries.info',
+      'filename' => 'example_info_file.libraries.info',
+      'name' => 'example_info_file.libraries',
+    ));
+    $this->assertEqual(libraries_scan_info_files(), $expected, 'libraries_scan_info_files() correctly finds the example info file.');
+    $this->verbose('<pre>' . var_export(libraries_scan_info_files(), TRUE) . '</pre>');
+  }
+
+  /**
+   * Tests libraries_info().
+   */
+  public function testLibrariesInfo() {
+    // Test that modules can provide and alter library information.
+    $info = libraries_info();
+    $this->assertTrue(isset($info['example_module']));
+    $this->verbose('Library:<pre>' . var_export($info['example_module'], TRUE) . '</pre>');
+    $this->assertEqual($info['example_module']['info type'], 'module');
+    $this->assertEqual($info['example_module']['module'], 'libraries_test_module');
+    $this->assertTrue($info['example_module']['module_altered']);
+
+    // Test that themes can provide and alter library information.
+    $this->assertTrue(isset($info['example_theme']));
+    $this->verbose('Library:<pre>' . var_export($info['example_theme'], TRUE) . '</pre>');
+    $this->assertEqual($info['example_theme']['info type'], 'theme');
+    $this->assertEqual($info['example_theme']['theme'], 'libraries_test_theme');
+    $this->assertTrue($info['example_theme']['theme_altered']);
+
+    // Test that library information is found correctly.
+    $expected = array(
+      'name' => 'Example files',
+      'library path' => drupal_get_path('module', 'libraries') . '/tests/libraries/example',
+      'version' => '1',
+      'files' => array(
+        'js' => array('example_1.js' => array()),
+        'css' => array('example_1.css' => array()),
+        'php' => array('example_1.php' => array()),
+      ),
+      'info type' => 'module',
+      'module' => 'libraries_test_module',
+    );
+    libraries_info_defaults($expected, 'example_files');
+    $library = libraries_info('example_files');
+    $this->verbose('Expected:<pre>' . var_export($expected, TRUE) . '</pre>');
+    $this->verbose('Actual:<pre>' . var_export($library, TRUE) . '</pre>');
+    $this->assertEqual($library, $expected, 'Library information is correctly gathered.');
+
+    // Test a library specified with an .info file gets detected.
+    $expected = array(
+      'name' => 'Example info file',
+      'info type' => 'info file',
+      'info file' => drupal_get_path('module', 'libraries') . '/tests/libraries/example_info_file.libraries.info',
+    );
+    libraries_info_defaults($expected, 'example_info_file');
+    $library = libraries_info('example_info_file');
+    // If this module was downloaded from Drupal.org, the Drupal.org packaging
+    // system has corrupted the test info file.
+    // @see http://drupal.org/node/1606606
+    unset($library['core'], $library['datestamp'], $library['project'], $library['version']);
+    $this->verbose('Expected:<pre>' . var_export($expected, TRUE) . '</pre>');
+    $this->verbose('Actual:<pre>' . var_export($library, TRUE) . '</pre>');
+    $this->assertEqual($library, $expected, 'Library specified with an .info file found');
+  }
+
+  /**
+   * Tests libraries_detect().
+   */
+  public function testLibrariesDetect() {
+    // Test missing library.
+    $library = libraries_detect('example_missing');
+    $this->verbose('<pre>' . var_export($library, TRUE) . '</pre>');
+    $this->assertEqual($library['error'], 'not found', 'Missing library not found.');
+    $error_message = t('The %library library could not be found.', array(
+      '%library' => $library['name'],
+    ));
+    $this->assertEqual($library['error message'], $error_message, 'Correct error message for a missing library.');
+
+    // Test unknown library version.
+    $library = libraries_detect('example_undetected_version');
+    $this->verbose('<pre>' . var_export($library, TRUE) . '</pre>');
+    $this->assertEqual($library['error'], 'not detected', 'Undetected version detected as such.');
+    $error_message = t('The version of the %library library could not be detected.', array(
+      '%library' => $library['name'],
+    ));
+    $this->assertEqual($library['error message'], $error_message, 'Correct error message for a library with an undetected version.');
+
+    // Test unsupported library version.
+    $library = libraries_detect('example_unsupported_version');
+    $this->verbose('<pre>' . var_export($library, TRUE) . '</pre>');
+    $this->assertEqual($library['error'], 'not supported', 'Unsupported version detected as such.');
+    $error_message = t('The installed version %version of the %library library is not supported.', array(
+      '%version' => $library['version'],
+      '%library' => $library['name'],
+    ));
+    $this->assertEqual($library['error message'], $error_message, 'Correct error message for a library with an unsupported version.');
+
+    // Test supported library version.
+    $library = libraries_detect('example_supported_version');
+    $this->verbose('<pre>' . var_export($library, TRUE) . '</pre>');
+    $this->assertEqual($library['installed'], TRUE, 'Supported library version found.');
+
+    // Test libraries_get_version().
+    $library = libraries_detect('example_default_version_callback');
+    $this->verbose('<pre>' . var_export($library, TRUE) . '</pre>');
+    $this->assertEqual($library['version'], '1', 'Expected version returned by default version callback.');
+
+    // Test a multiple-parameter version callback.
+    $library = libraries_detect('example_multiple_parameter_version_callback');
+    $this->verbose('<pre>' . var_export($library, TRUE) . '</pre>');
+    $this->assertEqual($library['version'], '1', 'Expected version returned by multiple parameter version callback.');
+
+    // Test a top-level files property.
+    $library = libraries_detect('example_files');
+    $files = array(
+      'js' => array('example_1.js' => array()),
+      'css' => array('example_1.css' => array()),
+      'php' => array('example_1.php' => array()),
+    );
+    $this->verbose('<pre>' . var_export($library, TRUE) . '</pre>');
+    $this->assertEqual($library['files'], $files, 'Top-level files property works.');
+
+    // Test version-specific library files.
+    $library = libraries_detect('example_versions');
+    $files = array(
+      'js' => array('example_2.js' => array()),
+      'css' => array('example_2.css' => array()),
+      'php' => array('example_2.php' => array()),
+    );
+    $this->verbose('<pre>' . var_export($library, TRUE) . '</pre>');
+    $this->assertEqual($library['files'], $files, 'Version-specific library files found.');
+
+    // Test missing variant.
+    $library = libraries_detect('example_variant_missing');
+    $this->verbose('<pre>' . var_export($library, TRUE) . '</pre>');
+    $this->assertEqual($library['variants']['example_variant']['error'], 'not found', 'Missing variant not found');
+    $error_message = t('The %variant variant of the %library library could not be found.', array(
+      '%variant' => 'example_variant',
+      '%library' => 'Example variant missing',
+    ));
+    $this->assertEqual($library['variants']['example_variant']['error message'], $error_message, 'Correct error message for a missing variant.');
+
+    // Test existing variant.
+    $library = libraries_detect('example_variant');
+    $this->verbose('<pre>' . var_export($library, TRUE) . '</pre>');
+    $this->assertEqual($library['variants']['example_variant']['installed'], TRUE, 'Existing variant found.');
+  }
+
+  /**
+   * Tests libraries_detect() without a $name parameter.
+   */
+  public function testLibrariesDetectAll() {
+    // Test that an array with all library information is returned and that the
+    // libraries are properly detected.
+    $libraries = libraries_detect();
+    $this->verbose('<pre>' . var_export($libraries, TRUE) . '</pre>');
+    $this->assertEqual($libraries['example_missing']['error'], 'not found');
+    $this->assertEqual($libraries['example_undetected_version']['error'], 'not detected');
+    $this->assertEqual($libraries['example_unsupported_version']['error'], 'not supported');
+    $this->assertEqual($libraries['example_supported_version']['installed'], TRUE);
+  }
+
+  /**
+   * Tests libraries_load().
+   */
+  public function testLibrariesLoad() {
+    // Test dependencies.
+    $library = libraries_load('example_dependency_missing');
+    $this->verbose('<pre>' . var_export($library, TRUE) . '</pre>');
+    $this->assertFalse($library['loaded'], 'Library with missing dependency cannot be loaded');
+    $library = libraries_load('example_dependency_incompatible');
+    $this->verbose('<pre>' . var_export($library, TRUE) . '</pre>');
+    $this->assertFalse($library['loaded'], 'Library with incompatible dependency cannot be loaded');
+    $library = libraries_load('example_dependency_compatible');
+    $this->verbose('<pre>' . var_export($library, TRUE) . '</pre>');
+    $this->assertEqual($library['loaded'], 1, 'Library with compatible dependency is loaded');
+    $loaded = &drupal_static('libraries_load');
+    $this->verbose('<pre>' . var_export($loaded, TRUE) . '</pre>');
+    $this->assertEqual($loaded['example_dependency']['loaded'], 1, 'Dependency library is also loaded');
+
+    // Test that PHP files that have a local $path variable do not break library
+    // loading.
+    // @see _libraries_require_once()
+    $library = libraries_load('example_path_variable_override');
+    $this->assertEqual($library['loaded'], 2, 'PHP files cannot break library loading.');
+  }
+
+  /**
+   * Tests the applying of callbacks.
+   */
+  public function testCallbacks() {
+    $expected = array(
+      'name' => 'Example callback',
+      'library path' => drupal_get_path('module', 'libraries') . '/tests/libraries/example',
+      'version' => '1',
+      'versions' => array(
+        '1' => array(
+          'variants' => array(
+            'example_variant' => array(
+              'info callback' => 'not applied',
+              'pre-detect callback' => 'not applied',
+              'post-detect callback' => 'not applied',
+              'pre-dependencies-load callback' => 'not applied',
+              'pre-load callback' => 'not applied',
+              'post-load callback' => 'not applied',
+            ),
+          ),
+          'info callback' => 'not applied',
+          'pre-detect callback' => 'not applied',
+          'post-detect callback' => 'not applied',
+          'pre-dependencies-load callback' => 'not applied',
+          'pre-load callback' => 'not applied',
+          'post-load callback' => 'not applied',
+        ),
+      ),
+      'variants' => array(
+        'example_variant' => array(
+          'info callback' => 'not applied',
+          'pre-detect callback' => 'not applied',
+          'post-detect callback' => 'not applied',
+          'pre-dependencies-load callback' => 'not applied',
+          'pre-load callback' => 'not applied',
+          'post-load callback' => 'not applied',
+        ),
+      ),
+      'callbacks' => array(
+        'info' => array('_libraries_test_module_info_callback'),
+        'pre-detect' => array('_libraries_test_module_pre_detect_callback'),
+        'post-detect' => array('_libraries_test_module_post_detect_callback'),
+        'pre-dependencies-load' => array('_libraries_test_module_pre_dependencies_load_callback'),
+        'pre-load' => array('_libraries_test_module_pre_load_callback'),
+        'post-load' => array('_libraries_test_module_post_load_callback'),
+      ),
+      'info callback' => 'not applied',
+      'pre-detect callback' => 'not applied',
+      'post-detect callback' => 'not applied',
+      'pre-dependencies-load callback' => 'not applied',
+      'pre-load callback' => 'not applied',
+      'post-load callback' => 'not applied',
+      'info type' => 'module',
+      'module' => 'libraries_test_module',
+    );
+    libraries_info_defaults($expected, 'example_callback');
+
+    // Test a callback in the 'info' group.
+    $expected['info callback'] = 'applied (top-level)';
+    $expected['versions']['1']['info callback'] = 'applied (version 1)';
+    $expected['versions']['1']['variants']['example_variant']['info callback'] = 'applied (version 1, variant example_variant)';
+    $expected['variants']['example_variant']['info callback'] = 'applied (variant example_variant)';
+    $library = libraries_info('example_callback');
+    $this->verbose('Expected:<pre>' . var_export($expected, TRUE) . '</pre>');
+    $this->verbose('Actual:<pre>' . var_export($library, TRUE) . '</pre>');
+    $this->assertEqual($library, $expected, 'Prepare callback was applied correctly.');
+
+    // Test a callback in the 'pre-detect' and 'post-detect' phases.
+    // Successfully detected libraries should only contain version information
+    // for the detected version and thus, be marked as installed.
+    unset($expected['versions']);
+    $expected['installed'] = TRUE;
+    // Additionally, version-specific properties of the detected version are
+    // supposed to override the corresponding top-level properties.
+    $expected['info callback'] = 'applied (version 1)';
+    $expected['variants']['example_variant']['installed'] = TRUE;
+    $expected['variants']['example_variant']['info callback'] = 'applied (version 1, variant example_variant)';
+    // Version-overloading takes place after the 'pre-detect' callbacks have
+    // been applied.
+    $expected['pre-detect callback'] = 'applied (version 1)';
+    $expected['post-detect callback'] = 'applied (top-level)';
+    $expected['variants']['example_variant']['pre-detect callback'] = 'applied (version 1, variant example_variant)';
+    $expected['variants']['example_variant']['post-detect callback'] = 'applied (variant example_variant)';
+    $library = libraries_detect('example_callback');
+    $this->verbose('Expected:<pre>' . var_export($expected, TRUE) . '</pre>');
+    $this->verbose('Actual:<pre>' . var_export($library, TRUE) . '</pre>');
+    $this->assertEqual($library, $expected, 'Detect callback was applied correctly.');
+
+    // Test a callback in the 'pre-dependencies-load', 'pre-load' and
+    // 'post-load' phases.
+    // Successfully loaded libraries should only contain information about the
+    // already loaded variant.
+    unset($expected['variants']);
+    $expected['loaded'] = 0;
+    $expected['pre-dependencies-load callback'] = 'applied (top-level)';
+    $expected['pre-load callback'] = 'applied (top-level)';
+    $expected['post-load callback'] = 'applied (top-level)';
+    $library = libraries_load('example_callback');
+    $this->verbose('Expected:<pre>' . var_export($expected, TRUE) . '</pre>');
+    $this->verbose('Actual:<pre>' . var_export($library, TRUE) . '</pre>');
+    $this->assertEqual($library, $expected, 'Pre-load and post-load callbacks were applied correctly.');
+    // This is not recommended usually and is only used for testing purposes.
+    drupal_static_reset('libraries_load');
+    // Successfully loaded library variants are supposed to contain the specific
+    // variant information only.
+    $expected['info callback'] = 'applied (version 1, variant example_variant)';
+    $expected['pre-detect callback'] = 'applied (version 1, variant example_variant)';
+    $expected['post-detect callback'] = 'applied (variant example_variant)';
+    $library = libraries_load('example_callback', 'example_variant');
+    $this->verbose('Expected:<pre>' . var_export($expected, TRUE) . '</pre>');
+    $this->verbose('Actual:<pre>' . var_export($library, TRUE) . '</pre>');
+    $this->assertEqual($library, $expected, 'Pre-detect and post-detect callbacks were applied correctly to a variant.');
+  }
+
+  /**
+   * Tests that library files are properly added to the page output.
+   *
+   * We check for JavaScript and CSS files directly in the DOM and add a list of
+   * included PHP files manually to the page output.
+   *
+   * @see _libraries_test_module_load()
+   */
+  public function testLibrariesOutput() {
+    // Test loading of a simple library with a top-level files property.
+    $this->drupalGet('libraries-test-module/files');
+    $this->assertLibraryFiles('example_1', 'File loading');
+
+    // Test loading of integration files.
+    $this->drupalGet('libraries-test-module/module-integration-files');
+    $this->assertRaw('libraries_test_module.js', 'Integration file loading: libraries_test_module.js found');
+    $this->assertRaw('libraries_test_module.css', 'Integration file loading: libraries_test_module.css found');
+    $this->assertRaw('libraries_test_module.inc', 'Integration file loading: libraries_test_module.inc found');
+    $this->drupalGet('libraries-test-module/theme-integration-files');
+    $this->assertRaw('libraries_test_theme.js', 'Integration file loading: libraries_test_theme.js found');
+    $this->assertRaw('libraries_test_theme.css', 'Integration file loading: libraries_test_theme.css found');
+    $this->assertRaw('libraries_test_theme.inc', 'Integration file loading: libraries_test_theme.inc found');
+
+    // Test loading of post-load integration files.
+    $this->drupalGet('libraries-test-module/module-integration-files-post-load');
+    // If the files were not loaded correctly, a fatal error occurs.
+    $this->assertResponse(200, 'Post-load integration files are loaded correctly.');
+
+    // Test version overloading.
+    $this->drupalGet('libraries-test-module/versions');
+    $this->assertLibraryFiles('example_2', 'Version overloading');
+
+    // Test variant loading.
+    $this->drupalGet('libraries-test-module/variant');
+    $this->assertLibraryFiles('example_3', 'Variant loading');
+
+    // Test version overloading and variant loading.
+    $this->drupalGet('libraries-test-module/versions-and-variants');
+    $this->assertLibraryFiles('example_4', 'Concurrent version and variant overloading');
+
+    // Test caching.
+    variable_set('libraries_test_module_cache', TRUE);
+    cache_clear_all('example_callback', 'cache_libraries');
+    // When the library information is not cached, all callback groups should be
+    // invoked.
+    $this->drupalGet('libraries-test-module/cache');
+    $this->assertRaw('The <em>info</em> callback group was invoked.', 'Info callback invoked for uncached libraries.');
+    $this->assertRaw('The <em>pre-detect</em> callback group was invoked.', 'Pre-detect callback invoked for uncached libraries.');
+    $this->assertRaw('The <em>post-detect</em> callback group was invoked.', 'Post-detect callback invoked for uncached libraries.');
+    $this->assertRaw('The <em>pre-load</em> callback group was invoked.', 'Pre-load callback invoked for uncached libraries.');
+    $this->assertRaw('The <em>post-load</em> callback group was invoked.', 'Post-load callback invoked for uncached libraries.');
+    // When the library information is cached only the 'pre-load' and
+    // 'post-load' callback groups should be invoked.
+    $this->drupalGet('libraries-test-module/cache');
+    $this->assertNoRaw('The <em>info</em> callback group was not invoked.', 'Info callback not invoked for cached libraries.');
+    $this->assertNoRaw('The <em>pre-detect</em> callback group was not invoked.', 'Pre-detect callback not invoked for cached libraries.');
+    $this->assertNoRaw('The <em>post-detect</em> callback group was not invoked.', 'Post-detect callback not invoked for cached libraries.');
+    $this->assertRaw('The <em>pre-load</em> callback group was invoked.', 'Pre-load callback invoked for cached libraries.');
+    $this->assertRaw('The <em>post-load</em> callback group was invoked.', 'Post-load callback invoked for cached libraries.');
+    variable_set('libraries_test_module_cache', FALSE);
+  }
+
+  /**
+   * Helper function to assert that a library was correctly loaded.
+   *
+   * Asserts that all the correct files were loaded and all the incorrect ones
+   * were not.
+   *
+   * @param $name
+   *   The name of the files that should be loaded. The current testing system
+   *   knows of 'example_1', 'example_2', 'example_3' and 'example_4'. Each name
+   *   has an associated JavaScript, CSS and PHP file that will be asserted. All
+   *   other files will be asserted to not be loaded. See
+   *   tests/example/README.txt for more information on how the loading of the
+   *   files is tested.
+   * @param $label
+   *   (optional) A label to prepend to the assertion messages, to make them
+   *   less ambiguous.
+   * @param $extensions
+   *   (optional) The expected file extensions of $name. Defaults to
+   *   array('js', 'css', 'php').
+   */
+  public function assertLibraryFiles($name, $label = '', $extensions = array('js', 'css', 'php')) {
+    $label = ($label !== '' ? "$label: " : '');
+
+    // Test that the wrong files are not loaded...
+    $names = array(
+      'example_1' => FALSE,
+      'example_2' => FALSE,
+      'example_3' => FALSE,
+      'example_4' => FALSE,
+    );
+    // ...and the correct ones are.
+    $names[$name] = TRUE;
+
+    // Test for the specific HTML that the different file types appear as in the
+    // DOM.
+    $html = array(
+      'js' => array('<script type="text/javascript" src="', '"></script>'),
+      'css' => array('@import url("', '");'),
+      // PHP files do not get added to the DOM directly.
+      // @see _libraries_test_load()
+      'php' => array('<li>', '</li>'),
+    );
+
+    foreach ($names as $name => $expected) {
+      foreach ($extensions as $extension) {
+        $filepath = drupal_get_path('module', 'libraries') . "/tests/libraries/example/$name.$extension";
+        // JavaScript and CSS files appear as full URLs and with an appended
+        // query string.
+        if (in_array($extension, array('js', 'css'))) {
+          $filepath = url('', array('absolute' => TRUE)) . $filepath . '?' . variable_get('css_js_query_string');
+        }
+        $raw = $html[$extension][0] . $filepath . $html[$extension][1];
+        if ($expected) {
+          $this->assertRaw($raw, "$label$name.$extension found.");
+        }
+        else {
+          $this->assertNoRaw($raw, "$label$name.$extension not found.");
+        }
+      }
+    }
+  }
+
+}

+ 78 - 0
sites/all/modules/contrib/dev/libraries/tests/LibrariesUnitTest.test

@@ -0,0 +1,78 @@
+<?php
+
+/**
+ * @file
+ * Contains LibrariesUnitTest.
+ *
+ * Simpletest automatically discovers test files using PSR-4. We cannot,
+ * however, declare a namespace for this class, as that would require PHP 5.3.
+ * To prepare the PHP 5.3 requirement and the usage of PSR-4 in 7.x-3.x, we
+ * place the test files in the correct directory already, but for now register
+ * them explicitly in libraries.info.
+ */
+
+/**
+ * Tests basic Libraries API functions.
+ */
+class LibrariesUnitTest extends DrupalUnitTestCase {
+
+  /**
+   * Provides metadata about this test.
+   *
+   * @return array
+   *   An array of test metadata with the following keys:
+   *   - name: The name of the test.
+   *   - description: The description of the test.
+   *   - group: The group of the test.
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'Libraries API unit tests',
+      'description' => 'Tests basic functions provided by Libraries API.',
+      'group' => 'Libraries API',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    drupal_load('module', 'libraries');
+    parent::setUp();
+  }
+
+  /**
+   * Tests libraries_get_path().
+   */
+  public function testLibrariesGetPath() {
+    // Note that, even though libraries_get_path() doesn't find the 'example'
+    // library, we are able to make it 'installed' by specifying the 'library
+    // path' up-front. This is only used for testing purposed and is strongly
+    // discouraged as it defeats the purpose of Libraries API in the first
+    // place.
+    $this->assertEqual(libraries_get_path('example'), FALSE, 'libraries_get_path() returns FALSE for a missing library.');
+  }
+
+  /**
+   * Tests libraries_prepare_files().
+   */
+  public function testLibrariesPrepareFiles() {
+    $expected = array(
+      'files' => array(
+        'js' => array('example.js' => array()),
+        'css' => array('example.css' => array()),
+        'php' => array('example.php' => array()),
+      ),
+    );
+    $library = array(
+      'files' => array(
+        'js' => array('example.js'),
+        'css' => array('example.css'),
+        'php' => array('example.php'),
+      ),
+    );
+    libraries_prepare_files($library, NULL, NULL);
+    $this->assertEqual($expected, $library, 'libraries_prepare_files() works correctly.');
+  }
+
+}

+ 64 - 0
sites/all/modules/contrib/dev/libraries/tests/LibrariesWebTestBase.test

@@ -0,0 +1,64 @@
+<?php
+
+/**
+ * @file
+ * Contains LibrariesWebTestBase.
+ *
+ * Simpletest automatically discovers test files using PSR-4. We cannot,
+ * however, declare a namespace for this class, as that would require PHP 5.3.
+ * To prepare the PHP 5.3 requirement and the usage of PSR-4 in 7.x-3.x, we
+ * place the test files in the correct directory already, but for now register
+ * them explicitly in libraries.info
+ */
+
+/**
+ * Base class for Libraries API web tests.
+ */
+abstract class LibrariesWebTestBase extends DrupalWebTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $profile = 'testing';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp('libraries', 'libraries_test_module');
+    theme_enable(array('libraries_test_theme'));
+  }
+
+  /**
+   * Retrieves a path making sure a set of permissions is required to access it.
+   *
+   * After calling this method, a user with the given permissions is logged in
+   * and the retrieved page is loaded into the internal browser.
+   *
+   * @param array $permissions
+   *   An array of permission names to assign to user. Note that the user always
+   *   has the default permissions derived from the "authenticated users" role.
+   * @param string $path
+   *   Drupal path or URL to load into the internal browser.
+   * @param array $options
+   *   Options to be forwarded to url().
+   * @param array $headers
+   *   An array containing additional HTTP request headers, each formatted as
+   *   "name: value".
+   *
+   * @return string
+   *   The retrieved HTML string, also available as $this->drupalGetContent().
+   *
+   * @see \DrupalWebTestCase::drupalGet()
+   * @see \DrupalWebTestCase::drupalCreateUser()
+   */
+  protected function getWithPermissions(array $permissions, $path, array $options = array(), array $headers = array()) {
+    $this->drupalGet($path, $options, $headers);
+    $this->assertResponse(403);
+
+    $this->drupalLogin($this->drupalCreateUser($permissions));
+    $this->drupalGet($path, $options, $headers);
+    $this->assertResponse(200);
+  }
+
+}

+ 43 - 0
sites/all/modules/contrib/dev/libraries/tests/libraries/example/README.txt

@@ -0,0 +1,43 @@
+
+Example library
+
+Version 1
+
+This file is an example file to test version detection.
+
+The various other files in this directory are to test the loading of JavaScript,
+CSS and PHP files.
+- JavaScript: The filenames of the JavaScript files are asserted to be in the
+  raw HTML via SimpleTest. Since the filename could appear, for instance, in an
+  error message, this is not very robust. Explicit testing of JavaScript,
+  though, is not yet possible with SimpleTest. To allow for easier debugging, we
+  place the following text on the page:
+  "If this text shows up, no JavaScript test file was loaded."
+  This text is replaced via JavaScript by a text of the form:
+  "If this text shows up, [file] was loaded successfully."
+  [file] is either 'example_1.js', 'example_2.js', 'example_3.js',
+  'example_4.js' or 'libraries_test_module.js'. If you have SimpleTest's verbose
+  mode enabled and see the above text in one of the debug pages, the noted
+  JavaScript file was loaded successfully.
+- CSS: The filenames of the CSS files are asserted to be in the raw HTML via
+  SimpleTest. Since the filename could appear, for instance, in an error
+  message, this is not very robust. Explicit testing of CSS, though, is not yet
+  possible with SimpleTest. Hence, the CSS files, if loaded, make the following
+  text a certain color:
+  "If one of the CSS test files has been loaded, this text will be colored:
+  - example_1: red
+  - example_2: green
+  - example_3: orange
+  - example_4: blue
+  - libraries_test_module: purple"
+  If you have SimpleTest's verbose mode enabled, and see the above text in a
+  certain color (i.e. not in black), a CSS file was loaded successfully. Which
+  file depends on the color as referenced in the text above.
+- PHP: The loading of PHP files is tested by defining a dummy function in the
+  PHP files and then checking whether this function was defined using
+  function_exists(). This can be checked programatically with SimpleTest.
+The loading of integration files is tested with the same method. The integration
+files are libraries_test_module.js, libraries_test_module.css,
+libraries_test_module.inc and are located in the test module's directory
+alongside libraries_test_module.info (i.e. they are not in the same directory as
+this file).

+ 12 - 0
sites/all/modules/contrib/dev/libraries/tests/libraries/example/example_1.css

@@ -0,0 +1,12 @@
+
+/**
+ * @file
+ * Test CSS file for Libraries loading.
+ *
+ * Color the 'libraries-test-module-css' div red. See README.txt for more
+ * information.
+ */
+
+.libraries-test-module-css {
+  color: red;
+}

+ 18 - 0
sites/all/modules/contrib/dev/libraries/tests/libraries/example/example_1.js

@@ -0,0 +1,18 @@
+
+/**
+ * @file
+ * Test JavaScript file for Libraries loading.
+ *
+ * Replace the text in the 'libraries-test-module-js' div. See README.txt for
+ * more information.
+ */
+
+(function ($) {
+
+Drupal.behaviors.librariesTest = {
+  attach: function(context, settings) {
+    $('.libraries-test-module-js').text('If this text shows up, example_1.js was loaded successfully.')
+  }
+};
+
+})(jQuery);

+ 15 - 0
sites/all/modules/contrib/dev/libraries/tests/libraries/example/example_1.php

@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * @file
+ * Test PHP file for Libraries loading.
+ */
+
+// @see _libraries_require_once()
+$path = 'abc';
+
+/**
+ * Dummy function to see if this file was loaded.
+ */
+function _libraries_test_module_example_1() {
+}

+ 12 - 0
sites/all/modules/contrib/dev/libraries/tests/libraries/example/example_2.css

@@ -0,0 +1,12 @@
+
+/**
+ * @file
+ * Test CSS file for Libraries loading.
+ *
+ * Color the 'libraries-test-module-css' div green. See README.txt for more
+ * information.
+ */
+
+.libraries-test-module-css {
+  color: green;
+}

+ 18 - 0
sites/all/modules/contrib/dev/libraries/tests/libraries/example/example_2.js

@@ -0,0 +1,18 @@
+
+/**
+ * @file
+ * Test JavaScript file for Libraries loading.
+ *
+ * Replace the text in the 'libraries-test-module-js' div. See README.txt for
+ * more information.
+ */
+
+(function ($) {
+
+Drupal.behaviors.librariesTest = {
+  attach: function(context, settings) {
+    $('.libraries-test-module-js').text('If this text shows up, example_2.js was loaded successfully.')
+  }
+};
+
+})(jQuery);

+ 15 - 0
sites/all/modules/contrib/dev/libraries/tests/libraries/example/example_2.php

@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * @file
+ * Test PHP file for Libraries loading.
+ */
+
+// @see _libraries_require_once()
+$path = 'abc';
+
+/**
+ * Dummy function to see if this file was loaded.
+ */
+function _libraries_test_module_example_2() {
+}

+ 12 - 0
sites/all/modules/contrib/dev/libraries/tests/libraries/example/example_3.css

@@ -0,0 +1,12 @@
+
+/**
+ * @file
+ * Test CSS file for Libraries loading.
+ *
+ * Color the 'libraries-test-module-css' div orange. See README.txt for more
+ * information.
+ */
+
+.libraries-test-module-css {
+  color: orange;
+}

+ 18 - 0
sites/all/modules/contrib/dev/libraries/tests/libraries/example/example_3.js

@@ -0,0 +1,18 @@
+
+/**
+ * @file
+ * Test JavaScript file for Libraries loading.
+ *
+ * Replace the text in the 'libraries-test-module-js' div. See README.txt for
+ * more information.
+ */
+
+(function ($) {
+
+Drupal.behaviors.librariesTest = {
+  attach: function(context, settings) {
+    $('.libraries-test-module-js').text('If this text shows up, example_3.js was loaded successfully.')
+  }
+};
+
+})(jQuery);

+ 12 - 0
sites/all/modules/contrib/dev/libraries/tests/libraries/example/example_3.php

@@ -0,0 +1,12 @@
+<?php
+
+/**
+ * @file
+ * Test PHP file for Libraries loading.
+ */
+
+/**
+ * Dummy function to see if this file was loaded.
+ */
+function _libraries_test_module_example_3() {
+}

+ 12 - 0
sites/all/modules/contrib/dev/libraries/tests/libraries/example/example_4.css

@@ -0,0 +1,12 @@
+
+/**
+ * @file
+ * Test CSS file for Libraries loading.
+ *
+ * Color the 'libraries-test-module-css' div blue. See README.txt for more
+ * information.
+ */
+
+.libraries-test-module-css {
+  color: blue;
+}

+ 18 - 0
sites/all/modules/contrib/dev/libraries/tests/libraries/example/example_4.js

@@ -0,0 +1,18 @@
+
+/**
+ * @file
+ * Test JavaScript file for Libraries loading.
+ *
+ * Replace the text in the 'libraries-test-module-js' div. See README.txt for
+ * more information.
+ */
+
+(function ($) {
+
+Drupal.behaviors.librariesTest = {
+  attach: function(context, settings) {
+    $('.libraries-test-module-js').text('If this text shows up, example_4.js was loaded successfully.')
+  }
+};
+
+})(jQuery);

+ 12 - 0
sites/all/modules/contrib/dev/libraries/tests/libraries/example/example_4.php

@@ -0,0 +1,12 @@
+<?php
+
+/**
+ * @file
+ * Test PHP file for Libraries loading.
+ */
+
+/**
+ * Dummy function to see if this file was loaded.
+ */
+function _libraries_test_module_example_4() {
+}

+ 10 - 0
sites/all/modules/contrib/dev/libraries/tests/libraries/example_info_file.libraries.info

@@ -0,0 +1,10 @@
+; This is an example info file of a library used for testing purposes.
+name = Example info file
+
+
+; Information added by Drupal.org packaging script on 2016-05-12
+version = "7.x-2.3"
+core = "7.x"
+project = "libraries"
+datestamp = "1463077450"
+

+ 12 - 0
sites/all/modules/contrib/dev/libraries/tests/modules/libraries_test_module/libraries_test_module.css

@@ -0,0 +1,12 @@
+
+/**
+ * @file
+ * Test CSS file for Libraries loading.
+ *
+ * Color the 'libraries-test-module-css' div purple. See README.txt for more
+ * information.
+ */
+
+.libraries-test-module-css {
+  color: purple;
+}

+ 11 - 0
sites/all/modules/contrib/dev/libraries/tests/modules/libraries_test_module/libraries_test_module.inc

@@ -0,0 +1,11 @@
+<?php
+
+/**
+ * @file
+ * Test PHP file for Libraries loading.
+
+/**
+ * Dummy function to see if this file was loaded.
+ */
+function _libraries_test_module_integration_file() {
+}

+ 13 - 0
sites/all/modules/contrib/dev/libraries/tests/modules/libraries_test_module/libraries_test_module.info

@@ -0,0 +1,13 @@
+name = Libraries test module
+description = Tests library detection and loading.
+core = 7.x
+package = Testing
+dependencies[] = libraries
+hidden = TRUE
+
+; Information added by Drupal.org packaging script on 2016-05-12
+version = "7.x-2.3"
+core = "7.x"
+project = "libraries"
+datestamp = "1463077450"
+

+ 18 - 0
sites/all/modules/contrib/dev/libraries/tests/modules/libraries_test_module/libraries_test_module.js

@@ -0,0 +1,18 @@
+
+/**
+ * @file
+ * Test JavaScript file for Libraries loading.
+ *
+ * Replace the text in the 'libraries-test-module-js' div. See README.txt for
+ * more information.
+ */
+
+(function ($) {
+
+Drupal.behaviors.librariesTest = {
+  attach: function(context, settings) {
+    $('.libraries-test-module-js').text('If this text shows up, libraries_test_module.js was loaded successfully.')
+  }
+};
+
+})(jQuery);

+ 631 - 0
sites/all/modules/contrib/dev/libraries/tests/modules/libraries_test_module/libraries_test_module.module

@@ -0,0 +1,631 @@
+<?php
+
+/**
+ * @file
+ * Tests the library detection and loading.
+ */
+
+/**
+ * Implements hook_libraries_info().
+ */
+function libraries_test_module_libraries_info() {
+  // Test library information gathering.
+  $libraries['example_module'] = array(
+    'name' => 'Example module',
+    'module_altered' => FALSE,
+  );
+
+  // Test library detection.
+  $libraries['example_missing'] = array(
+    'name' => 'Example missing',
+    // Provide a vendor and download URL to test that the UI links to it.
+    'vendor url' => 'http://example.com',
+    'download url' => 'http://example.com/download',
+    'library path' => drupal_get_path('module', 'libraries') . '/tests/libraries/missing',
+  );
+  $libraries['example_undetected_version'] = array(
+    'name' => 'Example undetected version',
+    'library path' => drupal_get_path('module', 'libraries') . '/tests/libraries/example',
+    'version callback' => '_libraries_test_module_return_version',
+    'version arguments' => array(FALSE),
+  );
+  $libraries['example_unsupported_version'] = array(
+    'name' => 'Example unsupported version',
+    // Provide a download URL to test that the UI links to it.
+    'download url' => 'http://example.com/download',
+    'library path' => drupal_get_path('module', 'libraries') . '/tests/libraries/example',
+    'version callback' => '_libraries_test_module_return_version',
+    'version arguments' => array('1'),
+    'versions' => array(
+      '2' => array(),
+    ),
+  );
+  $libraries['example_supported_version'] = array(
+    'name' => 'Example supported version',
+    'library path' => drupal_get_path('module', 'libraries') . '/tests/libraries/example',
+    'version callback' => '_libraries_test_module_return_version',
+    'version arguments' => array('1'),
+    'versions' => array(
+      '1' => array(),
+    ),
+  );
+
+  // Test the default version callback.
+  $libraries['example_default_version_callback'] = array(
+    'name' => 'Example default version callback',
+    'library path' => drupal_get_path('module', 'libraries') . '/tests/libraries/example',
+    'version arguments' => array(
+      'file' => 'README.txt',
+      // Version 1
+      'pattern' => '/Version (\d+)/',
+      'lines' => 5,
+    ),
+  );
+
+  // Test a multiple-parameter version callback.
+  $libraries['example_multiple_parameter_version_callback'] = array(
+    'name' => 'Example multiple parameter version callback',
+    'library path' => drupal_get_path('module', 'libraries') . '/tests/libraries/example',
+    // Version 1
+    'version callback' => '_libraries_test_module_get_version',
+    'version arguments' => array('README.txt', '/Version (\d+)/', 5),
+  );
+
+  // Test a top-level files property.
+  $libraries['example_files'] = array(
+    'name' => 'Example files',
+    'library path' => drupal_get_path('module', 'libraries') . '/tests/libraries/example',
+    'version' => '1',
+    'files' => array(
+      'js' => array('example_1.js'),
+      'css' => array('example_1.css'),
+      'php' => array('example_1.php'),
+    ),
+  );
+
+  // Test loading of integration files.
+  // Normally added by the corresponding module via hook_libraries_info_alter(),
+  // these files should be automatically loaded when the library is loaded.
+  $libraries['example_module_integration_files'] = array(
+    'name' => 'Example module integration files',
+    'library path' => drupal_get_path('module', 'libraries') . '/tests/libraries/example',
+    'version' => '1',
+    'integration files' => array(
+      'libraries_test_module' => array(
+        'js' => array('libraries_test_module.js'),
+        'css' => array('libraries_test_module.css'),
+        'php' => array('libraries_test_module.inc'),
+      ),
+    ),
+  );
+
+  // Test loading of integration files after library files.
+  // We test the correct loading order by calling a function that is defined in
+  // example_1.php in libraries_test_module_post_load.inc.
+  $libraries['example_module_integration_files_post_load'] = array(
+    'name' => 'Example module post-load integration files',
+    'library path' => drupal_get_path('module', 'libraries') . '/tests/libraries/example',
+    'version' => '1',
+    'files' => array(
+      'php' => array('example_1.php'),
+    ),
+    'integration files' => array(
+      'libraries_test_module' => array(
+        'php' => array('libraries_test_module_post_load.inc'),
+      ),
+    ),
+    'post-load integration files' => TRUE,
+  );
+
+  // Test version overloading.
+  $libraries['example_versions'] = array(
+    'name' => 'Example versions',
+    'library path' => drupal_get_path('module', 'libraries') . '/tests/libraries/example',
+    'version' => '2',
+    'versions' => array(
+      '1' => array(
+        'files' => array(
+          'js' => array('example_1.js'),
+          'css' => array('example_1.css'),
+          'php' => array('example_1.php'),
+        ),
+      ),
+      '2' => array(
+        'files' => array(
+          'js' => array('example_2.js'),
+          'css' => array('example_2.css'),
+          'php' => array('example_2.php'),
+        ),
+      ),
+    ),
+  );
+
+  // Test variant detection.
+  $libraries['example_variant_missing'] = array(
+    'name' => 'Example variant missing',
+    'library path' => drupal_get_path('module', 'libraries') . '/tests/libraries/example',
+    'version' => '1',
+    'variants' => array(
+      'example_variant' => array(
+        'files' => array(
+          'js' => array('example_3.js'),
+          'css' => array('example_3.css'),
+          'php' => array('example_3.php'),
+        ),
+        'variant callback' => '_libraries_test_module_return_installed',
+        'variant arguments' => array(FALSE),
+      ),
+    ),
+  );
+
+  $libraries['example_variant'] = array(
+    'name' => 'Example variant',
+    'library path' => drupal_get_path('module', 'libraries') . '/tests/libraries/example',
+    'version' => '1',
+    'variants' => array(
+      'example_variant' => array(
+        'files' => array(
+          'js' => array('example_3.js'),
+          'css' => array('example_3.css'),
+          'php' => array('example_3.php'),
+        ),
+        'variant callback' => '_libraries_test_module_return_installed',
+        'variant arguments' => array(TRUE),
+      ),
+    ),
+  );
+
+  // Test correct behaviour with multiple versions and multiple variants.
+  $libraries['example_versions_and_variants'] = array(
+    'name' => 'Example versions and variants',
+    'library path' => drupal_get_path('module', 'libraries') . '/tests/libraries/example',
+    'version' => '2',
+    'versions' => array(
+      '1' => array(
+        'variants' => array(
+          'example_variant_1' => array(
+            'files' => array(
+              'js' => array('example_1.js'),
+              'css' => array('example_1.css'),
+              'php' => array('example_1.php'),
+            ),
+            'variant callback' => '_libraries_test_module_return_installed',
+            'variant arguments' => array(TRUE),
+          ),
+          'example_variant_2' => array(
+            'files' => array(
+              'js' => array('example_2.js'),
+              'css' => array('example_2.css'),
+              'php' => array('example_2.php'),
+            ),
+            'variant callback' => '_libraries_test_module_return_installed',
+            'variant arguments' => array(TRUE),
+          ),
+        ),
+      ),
+      '2' => array(
+        'variants' => array(
+          'example_variant_1' => array(
+            'files' => array(
+              'js' => array('example_3.js'),
+              'css' => array('example_3.css'),
+              'php' => array('example_3.php'),
+            ),
+            'variant callback' => '_libraries_test_module_return_installed',
+            'variant arguments' => array(TRUE),
+          ),
+          'example_variant_2' => array(
+            'files' => array(
+              'js' => array('example_4.js'),
+              'css' => array('example_4.css'),
+              'php' => array('example_4.php'),
+            ),
+            'variant callback' => '_libraries_test_module_return_installed',
+            'variant arguments' => array(TRUE),
+          ),
+        ),
+      ),
+    ),
+  );
+
+  // Test dependency loading.
+  // We add one file to each library to be able to verify if it was loaded with
+  // libraries_load().
+  // This library acts as a dependency for the libraries below.
+  $libraries['example_dependency'] = array(
+    'name' => 'Example dependency',
+    'library path' => drupal_get_path('module', 'libraries') . '/tests/libraries/example',
+    'version' => '1.1',
+    'files' => array('js' => array('example_1.js')),
+  );
+  $libraries['example_dependency_missing'] = array(
+    'name' => 'Example dependency missing',
+    'library path' => drupal_get_path('module', 'libraries') . '/tests/libraries/example',
+    'version' => '1',
+    'dependencies' => array('example_missing'),
+    'files' => array('js' => array('example_1.js')),
+  );
+  $libraries['example_dependency_incompatible'] = array(
+    'name' => 'Example dependency incompatible',
+    'library path' => drupal_get_path('module', 'libraries') . '/tests/libraries/example',
+    'version' => '1',
+    'dependencies' => array('example_dependency (>1.1)'),
+    'files' => array('js' => array('example_1.js')),
+  );
+  $libraries['example_dependency_compatible'] = array(
+    'name' => 'Example dependency compatible',
+    'library path' => drupal_get_path('module', 'libraries') . '/tests/libraries/example',
+    'version' => '1',
+    'dependencies' => array('example_dependency (>=1.1)'),
+    'files' => array('js' => array('example_1.js')),
+  );
+
+  // Test the applying of callbacks.
+  $libraries['example_callback'] = array(
+    'name' => 'Example callback',
+    'library path' => drupal_get_path('module', 'libraries') . '/tests/libraries/example',
+    'version' => '1',
+    'versions' => array(
+      '1' => array(
+        'variants' => array(
+          'example_variant' => array(
+            // These keys are for testing purposes only.
+            'info callback' => 'not applied',
+            'pre-detect callback' => 'not applied',
+            'post-detect callback' => 'not applied',
+            'pre-dependencies-load callback' => 'not applied',
+            'pre-load callback' => 'not applied',
+            'post-load callback' => 'not applied',
+          ),
+        ),
+        // These keys are for testing purposes only.
+        'info callback' => 'not applied',
+        'pre-detect callback' => 'not applied',
+        'post-detect callback' => 'not applied',
+        'pre-dependencies-load callback' => 'not applied',
+        'pre-load callback' => 'not applied',
+        'post-load callback' => 'not applied',
+      ),
+    ),
+    'variants' => array(
+      'example_variant' => array(
+        // These keys are for testing purposes only.
+        'info callback' => 'not applied',
+        'pre-detect callback' => 'not applied',
+        'post-detect callback' => 'not applied',
+        'pre-dependencies-load callback' => 'not applied',
+        'pre-load callback' => 'not applied',
+        'post-load callback' => 'not applied',
+      ),
+    ),
+    'callbacks' => array(
+      'info' => array('_libraries_test_module_info_callback'),
+      'pre-detect' => array('_libraries_test_module_pre_detect_callback'),
+      'post-detect' => array('_libraries_test_module_post_detect_callback'),
+      'pre-dependencies-load' => array('_libraries_test_module_pre_dependencies_load_callback'),
+      'pre-load' => array('_libraries_test_module_pre_load_callback'),
+      'post-load' => array('_libraries_test_module_post_load_callback'),
+    ),
+    // These keys are for testing purposes only.
+    'info callback' => 'not applied',
+    'pre-detect callback' => 'not applied',
+    'post-detect callback' => 'not applied',
+    'pre-dependencies-load callback' => 'not applied',
+    'pre-load callback' => 'not applied',
+    'post-load callback' => 'not applied',
+  );
+
+  $libraries['example_path_variable_override'] = array(
+    'name' => 'Example path variable override',
+    'library path' => drupal_get_path('module', 'libraries') . '/tests/libraries/example',
+    'version' => '1',
+    'files' => array(
+      'php' => array('example_1.php', 'example_2.php'),
+    ),
+  );
+
+  return $libraries;
+}
+
+/**
+ * Implements hook_libraries_info_alter().
+ */
+function libraries_test_module_libraries_info_alter(&$libraries) {
+  $libraries['example_module']['module_altered'] = TRUE;
+}
+
+/**
+ * Implements hook_libraries_info_file_paths()
+ */
+function libraries_test_module_libraries_info_file_paths() {
+  return array(drupal_get_path('module', 'libraries') . '/tests/libraries');
+}
+
+/**
+ * Gets the version of an example library.
+ *
+ * Returns exactly the version string entered as the $version parameter. This
+ * function cannot be collapsed with _libraries_test_module_return_installed(),
+ * because of the different arguments that are passed automatically.
+ */
+function _libraries_test_module_return_version($library, $version) {
+  return $version;
+}
+
+/**
+ * Gets the version information from an arbitrary library.
+ *
+ * Test function for a version callback with multiple arguments. This is an
+ * exact copy of libraries_get_version(), which uses a single $option argument,
+ * except for the fact that it uses multiple arguments. Since we support both
+ * type of version callbacks, detecting the version of a test library with this
+ * function ensures that the arguments are passed correctly. This function might
+ * be a useful reference for a custom version callback that uses multiple
+ * parameters.
+ *
+ * @param $library
+ *   An associative array containing all information about the library.
+ * @param $file
+ *   The filename to parse for the version, relative to the library path. For
+ *   example: 'docs/changelog.txt'.
+ * @param pattern
+ *   A string containing a regular expression (PCRE) to match the library
+ *   version. For example: '/@version (\d+)\.(\d+)/'.
+ * @param lines
+ *   (optional) The maximum number of lines to search the pattern in. Defaults
+ *   to 20.
+ * @param cols
+ *   (optional) The maximum number of characters per line to take into account.
+ *   Defaults to 200. In case of minified or compressed files, this prevents
+ *   reading the entire file into memory.
+ *
+ * @return
+ *   A string containing the version of the library.
+ *
+ * @see libraries_get_version()
+ */
+function _libraries_test_module_get_version($library, $file, $pattern, $lines = 20, $cols = 200) {
+
+  $file = DRUPAL_ROOT . '/' . $library['library path'] . '/' . $file;
+  if (!file_exists($file)) {
+    return;
+  }
+  $file = fopen($file, 'r');
+  while ($lines && $line = fgets($file, $cols)) {
+    if (preg_match($pattern, $line, $version)) {
+      fclose($file);
+      return $version[1];
+    }
+    $lines--;
+  }
+  fclose($file);
+}
+
+/**
+ * Detects the variant of an example library.
+ *
+ * Returns exactly the value of $installed, either TRUE or FALSE. This function
+ * cannot be collapsed with _libraries_test_module_return_version(), because of
+ * the different arguments that are passed automatically.
+ */
+function _libraries_test_module_return_installed($library, $name, $installed) {
+  return $installed;
+}
+
+/**
+ * Sets the 'info callback' key.
+ *
+ * This function is used as a test callback for the 'info' callback group.
+ *
+ * @see _libraries_test_module_callback()
+ */
+function _libraries_test_module_info_callback(&$library, $version, $variant) {
+  _libraries_test_module_callback($library, $version, $variant, 'info');
+}
+
+/**
+ * Sets the 'pre-detect callback' key.
+ *
+ * This function is used as a test callback for the 'pre-detect' callback group.
+ *
+ * @see _libraries_test_module_callback()
+ */
+function _libraries_test_module_pre_detect_callback(&$library, $version, $variant) {
+  _libraries_test_module_callback($library, $version, $variant, 'pre-detect');
+}
+
+/**
+ * Sets the 'post-detect callback' key.
+ *
+ * This function is used as a test callback for the 'post-detect callback group.
+ *
+ * @see _libraries_test_module_callback()
+ */
+function _libraries_test_module_post_detect_callback(&$library, $version, $variant) {
+  _libraries_test_module_callback($library, $version, $variant, 'post-detect');
+}
+
+/**
+ * Sets the 'pre-dependencies-load callback' key.
+ *
+ * This function is used as a test callback for the 'pre-dependencies-load'
+ * callback group.
+ *
+ * @see _libraries_test_module_callback()
+ */
+function _libraries_test_module_pre_dependencies_load_callback(&$library, $version, $variant) {
+  _libraries_test_module_callback($library, $version, $variant, 'pre-dependencies-load');
+}
+
+/**
+ * Sets the 'pre-load callback' key.
+ *
+ * This function is used as a test callback for the 'pre-load' callback group.
+ *
+ * @see _libraries_test_module_callback()
+ */
+function _libraries_test_module_pre_load_callback(&$library, $version, $variant) {
+  _libraries_test_module_callback($library, $version, $variant, 'pre-load');
+}
+
+/**
+ * Sets the 'post-load callback' key.
+ *
+ * This function is used as a test callback for the 'post-load' callback group.
+ *
+ * @see _libraries_test_module_callback()
+ */
+function _libraries_test_module_post_load_callback(&$library, $version, $variant) {
+  _libraries_test_module_callback($library, $version, $variant, 'post-load');
+}
+
+/**
+ * Sets the '[group] callback' key, where [group] is prepare, detect, or load.
+ *
+ * This function is used as a test callback for the all callback groups.
+ *
+ * It sets the '[group] callback' (see above) key to 'applied ([part])' where
+ * [part] is either 'top-level', 'version x.y' (where x.y is the passed-in
+ * version string), 'variant example' (where example is the passed-in variant
+ * name), or 'version x.y, variant example' (see above), depending on the part
+ * of the library the passed-in library information belongs to.
+ *
+ * @param $library
+ *   An array of library information, which may be version- or variant-specific.
+ *   Passed by reference.
+ * @param $version
+ *   The version the library information passed in $library belongs to, or NULL
+ *   if the passed library information is not version-specific.
+ * @param $variant
+ *   The variant the library information passed in $library belongs to, or NULL
+ *   if the passed library information is not variant-specific.
+ */
+function _libraries_test_module_callback(&$library, $version, $variant, $group) {
+  $string = 'applied';
+  if (isset($version) && isset($variant)) {
+    $string .= " (version $version, variant $variant)";
+  }
+  elseif (isset($version)) {
+    $string .= " (version $version)";
+  }
+  elseif (isset($variant)) {
+    $string .= " (variant $variant)";
+  }
+  else {
+    $string .= ' (top-level)';
+  }
+  $library["$group callback"] = $string;
+
+  // The following is used to test caching of library information.
+  // Only set the message for the top-level library to prevent confusing,
+  // duplicate messages.
+  if (!isset($version) && !isset($variant) && variable_get('libraries_test_module_cache', FALSE)) {
+    drupal_set_message("The <em>$group</em> callback group was invoked.");
+  }
+}
+
+/**
+ * Implements hook_menu().
+ */
+function libraries_test_module_menu() {
+  $base = array(
+    'page callback' => '_libraries_test_module_load',
+    'access callback' => TRUE,
+  );
+  $items['libraries-test-module/files'] = $base + array(
+    'title' => 'Test files',
+    'page arguments' => array('example_files'),
+  );
+  $items['libraries-test-module/module-integration-files'] = $base + array(
+    'title' => 'Test module integration files',
+    'page arguments' => array('example_module_integration_files'),
+  );
+  $items['libraries-test-module/module-integration-files-post-load'] = $base + array(
+   'title' => 'Test module post-load integration files',
+    'page arguments' => array('example_module_integration_files_post_load'),
+  );
+  $items['libraries-test-module/theme-integration-files'] = $base + array(
+    'title' => 'Test theme integration files',
+    'page arguments' => array('example_theme_integration_files'),
+  );
+  $items['libraries-test-module/versions'] = $base + array(
+    'title' => 'Test version loading',
+    'page arguments' => array('example_versions'),
+  );
+  $items['libraries-test-module/variant'] = $base + array(
+    'title' => 'Test variant loading',
+    'page arguments' => array('example_variant', 'example_variant'),
+  );
+  $items['libraries-test-module/versions-and-variants'] = $base + array(
+    'title' => 'Test concurrent version and variant loading',
+    'page arguments' => array('example_versions_and_variants', 'example_variant_2'),
+  );
+  $items['libraries-test-module/cache'] = $base + array(
+    'title' => 'Test caching of library information',
+    'page arguments' => array('example_callback'),
+  );
+  return $items;
+}
+
+/**
+ * Loads a specified library (variant) for testing.
+ *
+ * JavaScript and CSS files can be checked directly by SimpleTest, so we only
+ * need to manually check for PHP files. We provide information about the loaded
+ * JavaScript and CSS files for easier debugging. See example/README.txt for
+ * more information.
+ */
+function _libraries_test_module_load($library, $variant = NULL) {
+  libraries_load($library, $variant);
+  // JavaScript and CSS files can be checked directly by SimpleTest, so we only
+  // need to manually check for PHP files.
+  $output = '';
+
+  // For easer debugging of JS loading, a text is shown that the JavaScript will
+  // replace.
+  $output .= '<h2>JavaScript</h2>';
+  $output .= '<div class="libraries-test-module-js">';
+  $output .= 'If this text shows up, no JavaScript test file was loaded.';
+  $output .= '</div>';
+
+  // For easier debugging of CSS loading, the loaded CSS files will color the
+  // following text.
+  $output .= '<h2>CSS</h2>';
+  $output .= '<div class="libraries-test-module-css">';
+  $output .= 'If one of the CSS test files has been loaded, this text will be colored:';
+  $output .= '<ul>';
+  // Do not reference the actual CSS files (i.e. including '.css'), because that
+  // breaks testing.
+  $output .= '<li>example_1: red</li>';
+  $output .= '<li>example_2: green</li>';
+  $output .= '<li>example_3: orange</li>';
+  $output .= '<li>example_4: blue</li>';
+  $output .= '<li>libraries_test_module: purple</li>';
+  $output .= '<li>libraries_test_theme: turquoise</li>';
+  $output .= '</ul>';
+  $output .= '</div>';
+
+  $output .= '<h2>PHP</h2>';
+  $output .= '<div class="libraries-test-module-php">';
+  $output .= 'The following is a list of all loaded test PHP files:';
+  $output .= '<ul>';
+  $files = get_included_files();
+  foreach ($files as $file) {
+    if (strpos($file, 'libraries/test') && !strpos($file, 'libraries_test_module.module') && !strpos($file, 'template.php')) {
+      $output .= '<li>' . str_replace(DRUPAL_ROOT . '/', '', $file) . '</li>';
+    }
+  }
+  $output .= '</ul>';
+  $output .= '</div>';
+
+  return $output;
+}
+
+/**
+ * Implements hook_system_theme_info().
+ */
+function libraries_test_module_system_theme_info() {
+  $themes = array();
+  $themes['libraries_test_theme'] = drupal_get_path('module', 'libraries') . '/tests/themes/libraries_test_theme/libraries_test_theme.info';
+  return $themes;
+}

+ 15 - 0
sites/all/modules/contrib/dev/libraries/tests/modules/libraries_test_module/libraries_test_module_post_load.inc

@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * @file
+ * Test PHP file for Libraries loading.
+
+/**
+ * Dummy function to see if this file was loaded.
+ */
+function _libraries_test_module_integration_file_post_load() {
+}
+
+// Call a function that is defined in the library file, to ensure that was
+// loaded prior to this file.
+_libraries_test_module_example_1();

+ 12 - 0
sites/all/modules/contrib/dev/libraries/tests/themes/libraries_test_theme/libraries_test_theme.css

@@ -0,0 +1,12 @@
+
+/**
+ * @file
+ * Test CSS file for Libraries loading.
+ *
+ * Color the 'libraries-test-module-css' div purple. See README.txt for more
+ * information.
+ */
+
+.libraries-test-module-css {
+  color: turquoise;
+}

+ 11 - 0
sites/all/modules/contrib/dev/libraries/tests/themes/libraries_test_theme/libraries_test_theme.inc

@@ -0,0 +1,11 @@
+<?php
+
+/**
+ * @file
+ * Test PHP file for Libraries loading.
+
+/**
+ * Dummy function to see if this file was loaded.
+ */
+function _libraries_test_theme_integration_file() {
+}

+ 11 - 0
sites/all/modules/contrib/dev/libraries/tests/themes/libraries_test_theme/libraries_test_theme.info

@@ -0,0 +1,11 @@
+name = Libraries test theme
+description = Tests that themes can provide and alter library information.
+core = 7.x
+hidden = TRUE
+
+; Information added by Drupal.org packaging script on 2016-05-12
+version = "7.x-2.3"
+core = "7.x"
+project = "libraries"
+datestamp = "1463077450"
+

+ 18 - 0
sites/all/modules/contrib/dev/libraries/tests/themes/libraries_test_theme/libraries_test_theme.js

@@ -0,0 +1,18 @@
+
+/**
+ * @file
+ * Test JavaScript file for Libraries loading.
+ *
+ * Replace the text in the 'libraries-test-module-js' div. See README.txt for
+ * more information.
+ */
+
+(function ($) {
+
+Drupal.behaviors.librariesTest = {
+  attach: function(context, settings) {
+    $('.libraries-test-module-js').text('If this text shows up, libraries_test_theme.js was loaded successfully.')
+  }
+};
+
+})(jQuery);

+ 36 - 0
sites/all/modules/contrib/dev/libraries/tests/themes/libraries_test_theme/template.php

@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * @file
+ * Libraries test theme.
+ */
+
+/**
+ * Implements hook_libraries_info().
+ */
+function libraries_test_theme_libraries_info() {
+  $libraries['example_theme'] = array(
+    'name' => 'Example theme',
+    'theme_altered' => FALSE,
+  );
+  $libraries['example_theme_integration_files'] = array(
+    'name' => 'Example theme integration file',
+    'library path' => drupal_get_path('module', 'libraries') . '/tests/libraries/example',
+    'version' => '1',
+    'integration files' => array(
+      'libraries_test_theme' => array(
+        'js' => array('libraries_test_theme.js'),
+        'css' => array('libraries_test_theme.css'),
+        'php' => array('libraries_test_theme.inc'),
+      ),
+    ),
+  );
+  return $libraries;
+}
+
+/**
+ * Implements hook_libraries_info_alter().
+ */
+function libraries_test_theme_libraries_info_alter(&$libraries) {
+  $libraries['example_theme']['theme_altered'] = TRUE;
+}

+ 339 - 0
sites/all/modules/contrib/fields/video_embed_field_overlay/LICENSE.txt

@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.

+ 69 - 0
sites/all/modules/contrib/fields/video_embed_field_overlay/README.txt

@@ -0,0 +1,69 @@
+SUMMARY:
+--------
+Allows videos embedded using the video_embed_field module to be displayed in a 
+DOM Window overlay.
+
+
+REQUIREMENTS:
+-------------
+* Libraries. http://drupal.org/project/libraries
+* DOM Window. http://drupal.org/project/domwindow
+* DOM Window jQuery Plugin. http://swip.codylindley.com/DOMWindowDemo.html
+* Image Cache Actions 7.x-1.0 http://drupal.org/project/imagecache_actions
+* System Stream Wrapper http://drupal.org/project/system_stream_wrapper
+* Video Embed.Field http://drupal.org/project/video_embed_field
+
+* System Stream Wrapper is only needed if you want to use ICA 7.x-1.1 or greater
+
+INSTALLATION:
+-------------
+* Install this module as usual.
+* Make sure the DOM Window is installed correctly and the jquery.DOMWindow was
+  downloaded correctly
+* If you haven't already done so, add a Video Embed field to one of your content
+  types.
+* When configuring the field if you enable the description field, it will be 
+  used as the link description if you choose not to show the thumbnail.
+* The Video Embed overlay settings can be tweaked in the Manage Display tab of 
+  your content type. For your video embed field, under the format column you
+  will be presented the usual options: Video Player and Thumbnail Preview and a
+  new option, provided by this module: Overlay.
+* When you change the format, different options will be presented to you in the
+  column to the right. So, click on overlay and notice that config settings will
+  be presented to you.
+* Click on the gear icon on the far right of that row to make the necessary 
+  display adjustments.
+
+CONFIGURATION:
+--------------
+* Video Style.
+  Description: Same behavior from the video_embed_field module. Controls the 
+  embedded player settings.
+  Default value: Normal.
+
+* Show Thumbnail. 
+  Description: Controls whether the thumbnail from the video service is 
+  displayed or not. If not, then a simple Play Button link will be shown instead
+  of the thumbnail.
+  Default value: Yes
+
+* Image Style.
+  Description: If selected, applies one of the available image styles to the
+  thumbnail image. Useful to overlay a play button on top of the thumbnail.
+  Default value: None (original image)
+
+COOL EXTRAS:
+------------
+* For extra oomph try the imagecache_actions module that extends the core image
+  functionality.
+
+$ drush dl imagecache_actions; drush en imagecache_canvasactions -y;
+
+ROAD MAP:
+---------
+* Future enhancements include:
+  - More customization of the settings via the user interface / admin screens.
+
+MAINTAINERS:
+------------
+* Rob Montero (rmontero) - http://drupal.org/user/191552

+ 7 - 0
sites/all/modules/contrib/fields/video_embed_field_overlay/css/video_embed_field_overlay.css

@@ -0,0 +1,7 @@
+#DOMWindow {
+  overflow: hidden !important;
+}
+
+.video-overlay-source {
+  display: none;
+}

+ 2 - 0
sites/all/modules/contrib/fields/video_embed_field_overlay/images/README.txt

@@ -0,0 +1,2 @@
+DEVELOPER'S NOTE: The spinners in this folder were generated at 
+http://www.preloaders.net/en/circular

BIN
sites/all/modules/contrib/fields/video_embed_field_overlay/images/loading_128.png


BIN
sites/all/modules/contrib/fields/video_embed_field_overlay/images/loading_16.png


BIN
sites/all/modules/contrib/fields/video_embed_field_overlay/images/video_overlay.png


+ 225 - 0
sites/all/modules/contrib/fields/video_embed_field_overlay/js/video_embed_field_overlay.js

@@ -0,0 +1,225 @@
+(function($) {
+  var console = window.console || false;
+  /**
+   * Finds the links to the videos and attaches the overlay behavior
+   */
+  Drupal.behaviors.videoEmbedFieldOverlay = {
+    ready: [],
+    timer: null,
+    players: {},
+    playOnPopUp: undefined,
+
+    /**
+     * Initial load function, preps videos for popup, sets up initial event chain.
+     */
+    attach: function (context, settings) {
+      Drupal.behaviors.videoEmbedFieldOverlay.players = $('.video-overlay-source iframe', context);
+
+      if ($.isFunction($.openDOMWindow)) {
+        Drupal.behaviors.videoEmbedFieldOverlay.players.each(function(i, element) {
+          if ($(element).attr('src').indexOf('vimeo.com') !== -1) {
+            Drupal.behaviors.videoEmbedFieldOverlay.vimeoProcessElement(element);
+          }
+        });
+
+        // Setup message handlers
+        if (window.addEventListener) { // all browsers except IE before version 9
+          window.addEventListener('message', Drupal.behaviors.videoEmbedFieldOverlay.onMessageReceived, false);
+        }
+        else if (window.attachEvent) { // IE before version 9
+          var attached = window.attachEvent('onmessage', Drupal.behaviors.videoEmbedFieldOverlay.onMessageReceived, false);
+          if (attached === false) {
+            if (console) {console.log('Failed to attach the listener');}
+          }
+        }
+
+        // Find all the trigger links
+        $('.video-overlay-thumbnail a.overlay', context).bind('click', function(e) {
+          // Prevent going to the URL
+          e.preventDefault();
+
+          // Get the id of the video
+          // @TODO: Find cleaner way to get this.
+          var id = $(this).parent().parent().find('.video-overlay-source iframe').attr('id').replace('overlay-video-', '');
+          Drupal.behaviors.videoEmbedFieldOverlay.videoOnClick(id);
+        });
+      } else {
+        if (console) {console.log('Cannot create DOMWindow');}
+      }
+    },
+
+    /**
+     * Triggers the DOM Windwow and the autoplay
+     */
+    videoOnClick: function (id) {
+      var f = $('iframe#overlay-video-' + id).parent().get(0) || $('iframe').parent().get(0);
+      var iframe = $('iframe#overlay-video-' + id).get(0) || $('iframe').get(0);
+
+      // Setup the DOM Window
+      $.openDOMWindow({
+        loader:0,
+        width:iframe.width || 640,
+        height:iframe.height || 360,
+        windowSourceID:f
+      });
+
+      // Play: Will not work on IE and some older versions of players.
+      if (Drupal.behaviors.videoEmbedFieldOverlay.browserSupported() === true) {
+        // Since we're moving the video from the page to the popup, we need to let the video know to
+        // start playing AFTER it's been loaded in the new place, instead of sending the command directly.
+        // We do this by telling this script which video to play once it's been loaded and ready to go.
+        Drupal.behaviors.videoEmbedFieldOverlay.playOnPopUp = 'overlay-video-' + id;
+      }
+    },
+    setupListeners: function (id) {
+      var f = $('iframe#' + id).get(0) || $('iframe').get(0),
+      url = '*';
+      if (f.contentWindow.postMessage) {
+        f.contentWindow.postMessage({
+          method: 'addEventListener',
+          value: 'play'
+        }, url);
+        f.contentWindow.postMessage({
+          method: 'addEventListener',
+          value: 'pause'
+        }, url);
+        f.contentWindow.postMessage({
+          method: 'addEventListener',
+          value: 'finish'
+        }, url);
+        Drupal.behaviors.videoEmbedFieldOverlay.setStatus(id, 'listening');
+        if (console) {console.log('Listeners setup for ' + id);}
+      } else {
+        if (console) {console.log('Browser does not support postMessage');}
+      }
+    },
+    /**
+     * Notes:
+     * The postMessage method is synchronous in Internet Explorer and 
+     * asynchronous in other browsers. 
+     */
+    play: function (id) {
+      var f = $('iframe#' + id).get(0) || $('iframe').get(0),
+      url = '*';
+
+      if (Drupal.behaviors.videoEmbedFieldOverlay.getStatus(id) !== 'play') {
+        if (f.contentWindow.postMessage) {
+          // Trigger video play
+          var messageData = JSON.stringify({method: 'play', player_id: id});
+          f.contentWindow.postMessage(messageData, url);
+        }
+        else {
+          if (console) {console.log('Your browser does not support the postMessage method!');}
+        }
+      }
+    },
+
+    /**
+     * Assigns a status to an array of player ids
+     */
+    setStatus: function (id, status) {
+      Drupal.behaviors.videoEmbedFieldOverlay.ready[id] = status;
+
+      if (console) {
+        console.log('Video: ' + id + ' is ' + status);
+      }
+
+      // react to certain events.
+      var eventHandler = 'onStatus' + status.charAt(0).toUpperCase() + status.slice(1);
+
+      if (Drupal.behaviors.videoEmbedFieldOverlay[eventHandler] !== undefined) {
+        Drupal.behaviors.videoEmbedFieldOverlay[eventHandler](id);
+      }
+    },
+
+    /**
+     * Retrieves the status for a given player id
+     */
+    getStatus: function (id) {
+      return Drupal.behaviors.videoEmbedFieldOverlay.ready[id];
+    },
+
+    /**
+     * Handles the messages received by the listener
+     */
+    onMessageReceived: function(e) {
+      var data = jQuery.parseJSON(e.data);
+      Drupal.behaviors.videoEmbedFieldOverlay.setStatus(data.player_id, data.event);
+    },
+
+    // Status event callbacks.
+
+    /**
+     * onStatusReady: Called when the video is ready to be interacted with.
+     */
+    onStatusReady: function(id) {
+      Drupal.behaviors.videoEmbedFieldOverlay.setupListeners(id);
+
+      if (Drupal.behaviors.videoEmbedFieldOverlay.playOnPopUp === id) {
+        Drupal.behaviors.videoEmbedFieldOverlay.playOnPopUp = undefined;
+        Drupal.behaviors.videoEmbedFieldOverlay.play(id);
+      }
+    },
+
+    /**
+     * onStatusFinish: Called when video playback is complete.
+     */
+    onStatusFinish: function(id) {
+      $.closeDOMWindow();
+    },
+
+    /**
+     * Checks to see if the current browser supports autoPlayback. Should be rewritten to use feature
+     * detection instead of browser sniffing.
+     */
+    browserSupported: function () {
+      if ($.browser.msie === true ) {
+        if (window.console) {window.console.log('IE does not support the autoplay feature');}
+        return false;
+      }
+      if ($.browser.mozilla === true && $.browser.version.slice(0,3) == '1.9') {
+        if (window.console) {window.console.log('Older versions of Mozilla do not support the autoplay feature');}
+        return false;
+      }
+      if ($.browser.opera === true) {
+        if (window.console) {window.console.log('Opera does not support the autoplay feature');}
+        return false;
+      }
+      return true;
+    },
+
+    /**
+     * Handles Vimeo-specific code on the embed element. 
+     *
+     * For Vimeo popup, we need to drop in an #id if there isn't one already, and we need to also let
+     * Vimeo know what the id is via a URL parameter. Also, we need to ensure that we let Vimeo know 
+     * that we want to use their JS API via another URL parameter. Written in a way that ensures we 
+     * don't lose any other url parameters passed in.
+     */
+    vimeoProcessElement: function(element) {
+      var src = $(element).attr('src');
+      var href = src.split('?')[0];
+      var videoID = href.split('/video/')[1];
+      
+      $(element).attr('id', 'overlay-video-' + videoID);
+
+      var urlAttributes = src.split('?')[1];
+      var urlAttributesObject = urlAttributes.split('&');
+      var urlKeyedAttributes = {};
+
+      for (var i in urlAttributesObject) {
+        var components = urlAttributesObject[i].split('=');
+        urlKeyedAttributes[components[0]] = components[1];
+      }
+
+      urlKeyedAttributes['api'] = 1;
+      urlKeyedAttributes['player_id'] = 'overlay-video-' + videoID;
+
+      var newURLAttributes = [];
+      for (i in urlKeyedAttributes) {
+        newURLAttributes.push(i + "=" + urlKeyedAttributes[i]);
+      }
+      $(element).attr('src', href + '?' + newURLAttributes.join('&'));
+    }
+  };
+})(jQuery);

+ 17 - 0
sites/all/modules/contrib/fields/video_embed_field_overlay/video_embed_field_overlay.info

@@ -0,0 +1,17 @@
+name = Video Embed Field Overlay
+description = Allows videos embedded using the video_embed_field module to be displayed in a DOM Window overlay.
+core = 7.x
+package = Media
+
+dependencies[] = video_embed_field
+dependencies[] = domwindow
+dependencies[] = imagecache_actions
+recommends[] = image
+suggests[] = imagecache_canvasactions
+
+; Information added by Drupal.org packaging script on 2014-03-19
+version = "7.x-1.5+1-dev"
+core = "7.x"
+project = "video_embed_field_overlay"
+datestamp = "1395241467"
+

+ 310 - 0
sites/all/modules/contrib/fields/video_embed_field_overlay/video_embed_field_overlay.module

@@ -0,0 +1,310 @@
+<?php
+
+/**
+ * Implements hook_theme().
+ */
+function video_embed_field_overlay_theme() {
+  return array(
+    'video_embed_field_overlay' => array(
+      'variables' => array(
+        'show_thumbnail' => TRUE,
+        'thumbnail_path' => NULL,
+        'description' => NULL,
+        'image_style' => NULL,
+        'video_url' => NULL,
+        'video_style' => 'normal',
+      ),
+    ),
+  );
+}
+
+/**
+ * Implements hook_field_formatter_info().
+ */
+function video_embed_field_overlay_field_formatter_info() {
+  return array(
+    'video_embed_field_overlay' => array(
+      'label' => t('Overlay'),
+      'field types' => array('video_embed_field'),
+      'settings' => array(
+        'show_thumbnail' => TRUE,
+        'video_style' => 'normal',
+        'image_style' => image_style_load('video_thumbnail') ? 'video_thumbnail' : 'none',
+        'description' => 1,
+        'overlay' => 'dom-window'),
+    ),
+  );
+}
+
+/**
+ * Implements hook_field_formatter_settings_form().
+ */
+function video_embed_field_overlay_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+  $element = array();
+
+  if ($display['type'] == 'video_embed_field_overlay') {
+    // Video style
+    $video_styles = video_embed_field_video_style_options(FALSE);
+    $element['video_style'] = array(
+      '#title' => t('Video style'),
+      '#type' => 'select',
+      '#default_value' => $settings['video_style'],
+      '#options' => $video_styles,
+    );
+    // Show an image?
+    $element['show_thumbnail'] = array(
+      '#title' => t('Show thumbnail'),
+      '#type' => 'select',
+      '#options' => array(1 => t('Yes'), 0 => t('No')),
+      '#default_value' => $settings['show_thumbnail'],
+    );
+    // Image style
+    $element['image_style'] = array(
+      '#title' => t('Image style'),
+      '#type' => 'select',
+      '#options' => image_style_options(FALSE),
+      '#default_value' => $settings['image_style'],
+      '#empty_option' => t('None (original image)'),
+    );
+
+    // Overlay library
+    $element['overlay'] = array(
+      '#title' => t('Overlay Library:'),
+      '#type' => 'select',
+      '#options' => array('dom-window' => t('DOM Window')),
+      '#default_value' => $settings['overlay'],
+    );
+  }
+
+  return $element;
+}
+
+/**
+ * Implements hook_field_formatter_settings_summary().
+ */
+function video_embed_field_overlay_field_formatter_settings_summary($field, $instance, $view_mode) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+
+  $summary = array();
+
+  if ($display['type'] == 'video_embed_field_overlay') {
+    // Video style
+    $video_styles = video_embed_field_video_style_options(FALSE);
+    // Styles could be lost because of enabled/disabled modules that defines
+    // their styles in code.
+    if (isset($video_styles[$settings['video_style']])) {
+      $summary[] = t('Video style: @style', array('@style' => $video_styles[$settings['video_style']]));
+    }
+
+    // Display thumbnail?
+    if (isset($settings['show_thumbnail']) && $settings['show_thumbnail'] == TRUE) {
+      $summary[] = t('Link: Showing thumbnail in link.');
+    }
+    else {
+      $summary[] = t('Link: Showing plain-text link.');
+    }
+
+    // Image style
+    $image_styles = image_style_options(FALSE);
+    if (isset($image_styles[$settings['image_style']])) {
+      $summary[] = t('Image style: @style', array('@style' => $image_styles[$settings['image_style']]));
+    } //No Image style (original image)
+    else {
+      $summary[] = t('Original Image.');
+    }
+
+    // Overlay
+    // @TODO: extend this to use a list of available overlay libraries.
+    if (isset($settings['overlay'])) {
+      $summary[] = t('Overlay Library: @overlay.', array('@overlay' => 'DOM Window'));
+    }
+    else {
+      $summary[] = t('Overlay Library: @overlay.', array('@overlay' => 'DOM Window'));
+    }
+  }
+
+  return implode('<br />', $summary);
+}
+
+/**
+ * Implements hook_field_formatter_view().
+ */
+function video_embed_field_overlay_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
+  $element = array();
+
+  foreach ($items as $delta => $item) {
+    if ($display['type'] == 'video_embed_field_overlay') {
+      if (!isset($item['description']) || empty($item['description'])) {
+        $item['description'] = t('Play video');
+      }
+      $element[$delta] = array(
+        '#theme' => 'video_embed_field_overlay',
+        '#thumbnail_path' => $item['thumbnail_path'],
+        '#image_style' => $display['settings']['image_style'],
+        '#video_url' => $item['video_url'],
+        '#description' => $item['description'],
+        '#show_thumbnail' => $display['settings']['show_thumbnail'],
+        '#video_style' => $display['settings']['video_style'],
+        '#attached' => array(
+          'css' => array(
+            drupal_get_path('module', 'video_embed_field_overlay') . '/css/video_embed_field_overlay.css',
+          ),
+        ),
+      );
+      if (video_embed_field_overlay_library_exists()) {
+        $element[$delta]['#attached']['library'] = array(array('domwindow', 'domwindow'));
+        $element[$delta]['#attached']['js'] = array(drupal_get_path('module', 'video_embed_field_overlay') . '/js/video_embed_field_overlay.js');
+        drupal_add_js(array(
+          'video_embed_field_overlay' => array(
+            'path' => drupal_get_path('module', 'video_embed_field_overlay'),
+          ),
+          ), 'setting');
+      }
+      else {
+        drupal_set_message(t('DOM Window library was not found.'), 'warning');
+      }
+    }
+  }
+
+  return $element;
+}
+
+/**
+ * Theme function wraps a video_embed_field element in an overlay
+ */
+function theme_video_embed_field_overlay(&$variables) {
+  $output = '';
+
+  if (isset($variables['show_thumbnail']) && $variables['show_thumbnail'] == TRUE) {
+    if (isset($variables['image_style']) && $variables['image_style']) {
+      $thumbnail = theme('image_style', array(
+        'path' => $variables['thumbnail_path'],
+        'style_name' => $variables['image_style']));
+    }
+    else {
+      $thumbnail = theme('image', array(
+        'path' => $variables['thumbnail_path'],
+        'alt' => $variables['description'],
+        ));
+    }
+  }
+
+  if (!isset($thumbnail) || empty($thumbnail)) {
+    $link = l($variables['description'], $variables['video_url'], array(
+      'attributes' => array(
+        'class' => array('overlay'),
+        'title' => $variables['description'],
+      ),
+      'html' => TRUE,
+      ));
+  }
+  else {
+    $link = l($thumbnail, $variables['video_url'], array(
+      'attributes' => array(
+        'class' => array('overlay'),
+      ),
+      'html' => TRUE,
+      ));
+  }
+
+  if (!isset($variables['video_style']) || empty($variables['video_style'])) {
+    $variables['video_style'] = 'normal';
+  }
+
+  $embed_code = theme('video_embed_field_embed_code', array(
+    'url' => $variables['video_url'],
+    'style' => $variables['video_style'],
+    ));
+
+  $output .= '<div class="video-overlay">';
+  $output .= '  <div class="video-overlay-thumbnail">';
+  $output .= '    ' . $link;
+  $output .= '  </div>';
+  $output .= '  <div class="video-overlay-source">';
+  $output .= '    ' . $embed_code;
+  $output .= '  </div>';
+  $output .= '</div>';
+  return $output;
+}
+
+/**
+ * Implements hook_image_default_styles().
+ */
+function video_embed_field_overlay_image_default_styles() {
+  $styles = array();
+
+  // Exported image style: video_thumbnail
+  $styles['video_thumbnail'] = array(
+    'name' => 'video_thumbnail',
+    'effects' => array(
+      1 => array(
+        'label' => 'Scale and crop',
+        'help' => 'Scale and crop will maintain the aspect-ratio of the original image, then crop the larger dimension. This is most useful for creating perfectly square thumbnails without stretching the image.',
+        'effect callback' => 'image_scale_and_crop_effect',
+        'dimensions callback' => 'image_resize_dimensions',
+        'form callback' => 'image_resize_form',
+        'summary theme' => 'image_resize_summary',
+        'module' => 'image',
+        'name' => 'image_scale_and_crop',
+        'data' => array(
+          'width' => '510',
+          'height' => '290',
+        ),
+        'weight' => '1',
+      ),
+    ),
+  );
+
+  // If the user has enabled the imagecache_canvasactions module, use it.
+  // @see http://drupal.org/project/imagecache_actions
+  if (module_exists('imagecache_canvasactions')) {
+    $styles['video_thumbnail']['effects'][] = array(
+      'label' => 'Overlay (watermark)',
+      'help' => 'Choose the file image you wish to use as an overlay, and position it in a layer on top of the canvas.',
+      'effect callback' => 'canvasactions_file2canvas_image',
+      'form callback' => 'canvasactions_file2canvas_form',
+      'summary theme' => 'canvasactions_file2canvas_summary',
+      'module' => 'imagecache_canvasactions',
+      'name' => 'canvasactions_file2canvas',
+      'data' => array(
+        'xpos' => 'center',
+        'ypos' => 'center',
+        'alpha' => '100',
+        // 'path' => drupal_get_path('module', 'video_embed_field_overlay') . '/images/video_overlay.png',
+        'path' => 'module://video_embed_field_overlay/images/video_overlay.png',
+      ),
+      'weight' => '2',
+    );
+  }
+
+  return $styles;
+}
+
+/**
+ * Implements hook_modules_enabled().
+ */
+function video_embed_field_overlay_modules_enabled($modules) {
+  if (in_array('imagecache_canvasactions', $modules)) {
+    drupal_static_reset('image_effect_definitions');
+    $style = image_style_load('video_thumbnail');
+    if ($style) {
+      image_default_style_revert($style);
+      drupal_set_message(t('Video Thumbnail image style has been reverted to its original state and the overlay action has been added.'));
+      image_flush_caches();
+    }
+  }
+}
+
+/**
+ * Helper function that checks if the domwindow library is present.
+ */
+function video_embed_field_overlay_library_exists() {
+  $libraries = array();
+  if (empty($libraries)) {
+    $libraries = libraries_get_libraries();
+  }
+  return array_key_exists('jquery.domwindow', $libraries);
+}

+ 170 - 0
sites/all/modules/contrib/files/imagecache_actions/CHANGELOG.txt

@@ -0,0 +1,170 @@
+Imagecache Actions
+------------------
+
+Imagecache Actions 7.x-1.x-dev
+------------------------------
+
+Imagecache Actions 7.x-1.7
+--------------------------
+- [#2671526]: Fatal error on image style flush when image styles are defined in
+  Features.
+
+Imagecache Actions 7.x-1.6
+--------------------------
+- [#2664020]: IE fails to display images whose extension and Content-Type header
+  do not match the actual image type.
+- [#1591484]: Underlay not working (on IM).
+- [#2359523]: Follow up to improve help text.
+- [#2615986] by hargobind: Effect summary in image_styles_admin.module.
+- Notice: Undefined index: element in theme_coloractions_alpha_summary() (line
+  98 of coloractions\transparency.inc).
+- Removed superfluous theme entry 'imagecache_subroutine_summary' from
+  autorotate sub module.
+- [#2080877] by heathdutton: Interlace / Progressive effect.
+- [#760438] by fietserwin: Resize Overlay / Watermark for ImageMagick.
+- [#760438] by raintonr, Ace Cooper, ttkaminski, thijsvdanker, fietserwin:
+  Resize Overlay / Watermark (GD only).
+- [#768980] by idebr, fietserwin: Blur effect.
+- [#2636314]: 'Import style' can fail on newline characters.
+- [#2573225]: Resize by percentage not calculating other field.
+- [#2447419]: Correct erroneous call to module_load_include in
+  imagecache_canvasactions.module.
+- [#2416805]: Remove reference to non-existent imagecache_coloractions.install.
+- [#2416805]: remove deprecated jquery attr() and replace with FAPI #states
+  (rounded corners UI form).
+- [#2580805]: Coding standards corrections.
+
+
+Imagecache Actions 7.x-1.5 2014-11-29
+-------------------------------------
+- [#2366163]: autorotate sometimes doesn't work with ImageMagick.
+- Text effect: small clean-up of hook_exit().
+- [#2379359]: image_imagemagick_overlay() passes a stream wrapper to convert.
+- [#2359523]: Overlay: allow to define offsets from all sides.
+- [#1717436]: Add effects: color level adjustment and desaturate while retaining
+    alpha.
+- [#2278233]: Call to undefined function imagecache_actions_get_style_label().
+- [#2183721]: Duplicate/Export links just edit, they don't duplicate or export.
+    possible solution only.
+- [#2176727]: New actions: scale / resize by percent.
+- [#2190759]: hook_image_style_flush(): Prefer silent failure over clear failure.
+- [#2166715]: Typo causes extra query every page load.
+- [#2139091]: # sign before HEX in settings form breaks Define canvas action.
+- [#2085967]: Remove .gitignore from version control.
+- Text overlay: treat empty texts as normal situation.
+- [#2003446]: Clean up or remove .install files, adapt .info files.
+- [1854270-48]: Minor optimization for Posterize.
+- Refactor: eliminate test warnings and errors.
+- Refactor: standardize function and parameter naming, function order, doxygen
+    documentation and comments, remove spelling errors in doc and comments.
+
+
+Imagecache Actions 7.x-1.4 2013-08-24
+-------------------------------------
+- [#1778214]: Remove project from image_effects_text_test.info
+- [#1854270]: Posterize action for file size/bandwidth saving on PNGs.
+- [#2060173]: Support image labels (introduced by D7.23).
+- Cleaned up the output of image style export. Id's and help texts are not used
+  on import, so don't have to be exported.
+- Repaired farbtastic colorpicker. It seems the library invocation changed
+  sometime in history. Rebuilt the color picker form to use #attached libraries
+  and simpler inline script instead. REMOVED the theme function that is now
+  redundant as #attached is a better way than drupal_add_js.
+- [#1152736]: Support tokens in text actions for images.
+- [#2025631]: Imagecache Testsuite refers to non-existent permissions.
+- Drupal.org went from http to https: changed all links in our documentation and
+  code.
+- Added ImageEffects as other image effect providing module.
+
+
+Imagecache Actions 7.x-1.3 2013-06-04
+-------------------------------------
+- Removed some errors and warnings from the test suite code (but not all).
+- [#2010560]: Fix spelling for "Update 7001".
+
+
+Imagecache Actions 7.x-1.2 2013-06-01
+-------------------------------------
+- [#1830130]: Allow file fields as referring entities in effects with context.
+- [#1446160]: Integrate with media module: Title and Alt text.
+- [#1591198]: Have dimensions calculations not ignore NULL's.
+- Refactored canvas effects: added parameter types in documentation and
+  signatures. Standardized function documentation. Comments according to Drupal
+  coding standards.
+- [#1999140]: Canvas effects using imagemagick might fail due to earlier
+  -gravity settings.
+- Refactored the image_effects_text_test module to no longer depend on features.
+- [#1998354]: Non-ASCII characters fail to display correctly on many systems
+  (when using Imagemagick).
+- Further code enhancements (messages, comments) to autorotate.
+- [#1930728]: Autorotate does not reset EXIF orientation tag.
+- [#1990620] Many config form docs missing from the D7 upgrade. Converted all
+  legacy instances of #type=markup into #markup='content..'
+- Removed deprecated functions imagecache_actions_entities_from_references() and
+  imagecache_actions_fields_from_filepath() (see [#1844298]).
+- [#1983168]: Custom text via PHP causing EntityMalformedException ...
+- Replaced lhandw.ttf font with some real free fonts that may also be
+  distributed for free. Changed all text effect tests accordingly.
+- Better text effect defaults (translated sample text, text visible by default,
+  sample font file).
+- [#1986304]: Strict warning: Only variables should be passed by reference ...
+- [#1981490]: Wrong filename imagecache_Actions.install.
+- [#1858760]: Unable to find the file 'lhandw.ttf'. Please check the path.
+
+
+Imagecache Actions 7.x-1.1 2012-12-04
+-------------------------------------
+- [#1591198]: Image dimensions callbacks should handle unknown (NULL) dimensions
+  as valid input.
+- [#464092]: Aspect Switcher -- Need to Flush Presets. Side-effect: now allows
+  to define no image style for either landscape or portrait.
+- [#1676924]: Autorotate: check for exif extension and test dimensions callback.
+- [#1849020]: Cant get text test examples to work.
+- [#1702716]: System Stream Wrappers Conflict.
+- [#1844298]: Remove dependency from entity module.
+- [#1778594]: Negative image effect does not work.
+- [#1778214]: Remove version from image_effects_text_test.info.
+- [#1752664]: Error on importing image style.
+- [#1676924]: Autorotate: check for exif extension.
+- [#1666912] by Dubs: Call to undefined function.
+  imagecache_actions_get_image_context() in imagecache_customactions.module.
+- [#1630194]: Custom actions broken after upgrading from dev to prod.
+- [#1591484] by epieddy: Underlay Center or Right parameter not working.
+- Moved the image styles administrative features to its own module.
+- Augment the duplicate with an export and import. This will allow users to
+  duplicate between sites or to post failing styles in the issue queue (without
+  using the features module).
+- Backport of patch from geoffreyr for [#1403962]: Add action "duplicate" to
+  image style admin screen. This will allow us to easily create large sets of
+  test/showcase styles and to fine tune this request before it lands in D8 core.
+
+
+Imagecache Actions 7.x-1.0 2012-05-19
+-------------------------------------
+Incompatibilities:
+- Effects that operate on the transparency layer, do not automatically change
+  the format anymore to png. You will have to add this as a separate effect.
+- File handling: the way that files (e.g. fonts, watermarks, backgrounds) are
+  searched for has been aligned over all effects that work with an additional
+  file. This may cause current styles to not being able to find specified files
+  anymore.
+- Custom actions: custom snippets are now executed using the PHP filter module,
+  meaning that the image style editor must have the 'Use PHP for settings'
+  permission to be able to edit the custom action snippet.
+- Custom actions: information and variables that are available in your custom
+  snippet have changed. See the README.txt of the custom actions module.
+
+No changelog exists from before this 7.x-1.0 version. So the changelog starts
+from here. 7.x-1.0 is the first reasonably well working D7 version. The 7.x-0.0
+version was based on posted patches in the D7 port request issue and has never
+been tested well. This 7.x-1.0 version is also not extensively tested by the
+maintainers, but has been used in many (live) sites - currently (may 2012) over
+5.000 reported 7.x-1.x-dev installs - so has received fairly good "test
+coverage".
+
+
+Current and past maintainers for Imagecache Actions
+---------------------------------------------------
+- dman (https://drupal.org/user/33240)
+- sidneyshan (https://drupal.org/user/652426)
+- fietserwin (https://drupal.org/user/750928)

+ 339 - 0
sites/all/modules/contrib/files/imagecache_actions/LICENSE.txt

@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.

+ 225 - 0
sites/all/modules/contrib/files/imagecache_actions/README.txt

@@ -0,0 +1,225 @@
+README for the Imagecache Actions Drupal module
+-----------------------------------------------
+
+Project page: https://drupal.org/project/imagecache_actions
+
+Current and past maintainers for Imagecache Actions:
+- dman (https://drupal.org/user/33240)
+- sidneyshan (https://drupal.org/user/652426)
+- fietserwin (https://drupal.org/user/750928)
+
+
+Release notes for 7.x-1.x-dev
+-----------------------------
+- Clear all caches after updating.
+
+
+Release notes for 7.x-1.4
+-------------------------
+- This release supports image labels as introduced by Drupal 7.23.
+- See CHANGELOG.txt for a full overview of changes.
+
+
+Release notes for 7.x-1.1
+-------------------------
+- If you use the module:// notation anywhere in an image effect, you must now
+  install the System Stream Wrapper module
+  (https://drupal.org/project/system_stream_wrapper).
+- Clear the cache after updating.
+
+
+Release notes for 7.x-1.0
+-------------------------
+- Clear the (registry) cache after installing or updating to 7.x-1.0.
+- If you use custom actions, run update.php.
+- If you use custom actions, be sure to enable the 'PHP filter' module and give
+  image style editors that may create custom actions the 'use PHP for settings'
+  permission. The module must also be enabled on image creation.
+- If you use custom actions, please read the README.txt from that sub-module to
+  find out about how information and resources are available to you. You will
+  probably have to change your code snippets.
+- If you use effects that use files (mask, overlays, underlays, text fonts),
+  check the way they are specified. From 7.x-1.0 on, you have to specify the
+  location using one of the schemes private://, public://, module:// or
+  temporary://. If no scheme is specified, the file is searched for as is, thus
+  relative to the current directory or as an absolute path.
+- Effects that use the transparency layer (e.g. mask, rounded corners) do not
+  automatically convert to PNG anymore. Use the "Change file format" for that.
+- There's no upgrade from D6. You will have to recreate your styles manually.
+
+Warning:
+  Ongoing development in the area of e.g. making the effects more consistent,
+  adding and/or removing parameters or redefining their meaning, might cause
+  backward incompatibilities between future versions and the current version.
+  Thus, we cannot and do not guarantee backwards compatibility or automatic
+  upgrade paths for future versions.
+
+
+Introduction
+------------
+The Imagecache Actions module provides a suite of additional image effects that
+can be added to image styles. Image styles let you create derivations of images
+by applying (a series of) effect(s) to it. Think of resizing, desaturating,
+masking, etc.
+
+Furthermore, imagecache_actions extends the administrative interface for image
+styles by providing additional features. It does so in the "Image styles admin"
+sub module.
+
+The additional effects that Imagecache Actions provides include:
+- Watermark: place a image with transparency anywhere over a source picture.
+- Overlay: add photo-corners etc to the image
+- Text overlay: add e.g. a copyright notice to your image.
+- Color-shifting: colorize images.
+- Brighten/Darken.
+- Alpha blending: use a gray scale image to define the transparency layer of an
+  image.
+- Canvas manipulation: resize the canvas and add a background color or image.
+- File Format switcher: if you need transparency in JPGs, make them PNG. If your
+  PNG thumbnails are 30K each, save them as JPGs.
+- Rounded corners.
+- TODO: complete list, check short descriptions
+
+These effects are grouped in sub-modules. Just enable the ones you want to use.
+TODO: list sub-modules and their sets of effects.
+
+Imagecache Actions supports both the GD toolkit from Drupal core and the
+Imagemagick toolkit. However, please note that Imagemagick support is not yet
+complete. Please file an issue if you encounter problems in using Imagemagick.
+
+
+What is imagecache_action not?
+------------------------------
+Imagecache Actions does not provide a new UI or new menu items. It hooks into
+the already existing image styles system (from Drupal core). See
+https://drupal.org/documentation/modules/image for more information about
+working with images.
+
+
+A note about the name of this module
+------------------------------------
+Image styles are part of Drupal 7 core and are the successor of the Drupal 6
+imagecache module. In Drupal 6 image styles were called (imagecache) presets and
+the separate effects that made up a style were called (imagecache) actions. In
+porting to D7, that name has not been changed (yet).
+
+
+Which toolkit to use?
+---------------------
+Personally, I (fietserwin) prefer the imagemagick toolkit:
+- It is better in anti-aliasing. Try to rotate an image using both toolkits and
+  you will see what I mean.
+- It does not execute in the PHP memory space, so is not restricted by the
+  memory_limit PHP setting.
+- The GD toolkit will, at least on my Windows configuration, keep the font file
+  open after a text operation, so you cannot delete, move or rename it anymore.
+
+On the other hand: the GD toolkit is always available (in the correct version),
+whereas imagemagick is not always present on shared hosting or may be present in
+an antique version that might give problems.
+
+Please note that effects may give different results depending on the
+toolkit used.
+
+Please also note that a 3rd image toolkit exists:
+  Imagick (https://www.drupal.org/project/imagick)
+This toolkit uses the Imagick extension and thus does not call the ImageMagick
+binaries directly. However our module does not implement the toolkit specific
+parts for the effects we provide for the Imagick toolkit, but the Imagick
+toolkit comes with its own set of effects that partly covers our effects. So,
+depending on the effects you require it may be a replacement for both our module
+and the Imagemagick module or the core GD toolkit.
+
+Hard Dependencies
+-----------------
+- Image module from Drupal core
+
+At least 1 of the available image toolkits:
+- GD toolkit from Drupal core.
+- Imagemagick toolkit: https://drupal.org/project/imagemagick.
+
+
+Soft Dependencies
+-----------------
+- System stream wrapper (https://drupal.org/project/system_stream_wrapper)
+- Remote stream wrapper (https://drupal.org/project/remote_stream_wrapper)
+These modules provide additional stream wrappers. Especially the system stream
+wrapper is very handy as it provides, among others, a module:// and theme://
+wrapper.
+
+
+Installing
+----------
+As usual.
+
+
+Usage
+-----
+After enabling the module:
+- Assure that the Image module from core is enabled.
+- Configure your toolkit and its settings at admin/config/media/image-toolkit.
+- Define image styles at admin/config/media/image-styles and add 1 or more
+  effects as defined by this module
+- Use the image styles via e.g. the formatters of image fields.
+
+
+Upgrading from D6
+-----------------
+There's no upgrade path defined for sites upgrading from D6 to D7. This means
+that you will have to manually redefine your D6 imagecache presets as D7 image
+styles. Note that actually an upgrade path would have to be defined by the
+imagecache module, not this imagecache actions module. However, as there is no
+D7 version of imagecache that provides an upgrade, users may post an upgrade
+function to the issue queue and we will incorporate it.
+
+
+Backwards compatibility
+-----------------------
+Future releases will not be guaranteed to be backwards compatible. Implementing
+Imagemagick support e.g. might give unforeseen problems that can only be solved
+by changing the details of what an effect does. We will document these kind of
+incompatibilities in the changelog and the release notes.
+
+
+File form fields
+----------------
+A number of effects have a file form field where the editor can define a file
+name to use. This can be e.g. for overlays, masks or fonts. The file name should
+be defined using either:
+- 1 of the (enabled) scheme's:
+  * public://
+  * private:// Preferred for site specific masks, overlays, etc, that do not
+    need to be shared publicly.
+  * temporary:// Unlikely to be useful, but supported anyway as all schemes are
+    supported.
+  * module:// Introduced by the system stream wrapper module and preferred for
+    module provided resources.
+  * theme:// idem.
+  * profile:// idem.
+  * library:// idem.
+- A relative (to the current directory, probably Drupal root) or absolute path.
+
+
+Support
+-------
+Via the issue queue of this project at Drupal.org.
+
+
+Known problems
+--------------
+These are better documented in the issue queue, but might be listed here (as
+well).
+
+- Underlay does not work in imagemagick if the dimensions of both images are not
+  equal. As a workaround first add a canvas effect with a fully transparent
+  background.
+- Underlay/overlay: keywords in the x and y offset fields do not work.
+- Underlay does still display a message about Imagemagick not being supported.
+- Brightness values outside the -250 .. 250 range are accepted.
+- Check color fields that allow a transparency component or allow to be empty to
+  specify fully transparent.
+
+Known problems: Imagemagick
+---------------------------
+- Define canvas using offsets may bot work on older versions. We have an error
+  report for version 6.5.4.7 (2009-07) (https://drupal.org/node/888644).

+ 112 - 0
sites/all/modules/contrib/files/imagecache_actions/ROADMAP.txt

@@ -0,0 +1,112 @@
+Imagecache Actions roadmap
+--------------------------
+
+This is a non-contractual roadmap for the D7 branch of the imagecache actions
+module. Actual release dates and completed features will largely depend on
+available time. So support is always welcome. Furthermore, critical bugs may
+make us release more often, but that should only change the release number in
+which certain features are planned, not the timeline.
+
+
+Imagecache Actions 7.x-1.0
+--------------------------
+Targeted release date: may 2012
+
+- (DONE) Clean up D7 issue queue
+- (DONE) Commit posted patches from the issue queue
+- (DONE) Solve easy to solve bug reports
+- Do some basic testing
+- (DONE) Reintroduce the text action, currently living in a sandbox project at
+  https://drupal.org/node/1090312
+- (DONE) Update README.txt
+- (DONE) Introduce CHANGELOG.txt
+- (DONE) Add this ROADMAP.txt
+
+
+Imagecache Actions 7.x-1.1
+--------------------------
+Targeted release date: end 2012
+
+Mainly a bug fix release
+- (DONE) Solve remaining outstanding bug reports
+- (ALMOST DONE) Keep D7 issue queue clean
+
+
+Imagecache Actions 7.x-1.2
+--------------------------
+Targeted release date: spring 2013
+
+- Check help and documentation. a.o: hook_help, effect descriptions.
+- (DONE) Continue to keep the D7 issue queue clean.
+- Improve Imagemagick support and/or document what effects are not working for
+  which toolkit (version).
+- (ALMOST DONE) Check that all effects implement all of the effects API (especially the
+  dimensions callback).
+- Add testing. The idea is to create a set of image styles that cover all
+  effects and can be used to visually check for regressions.
+
+  Automated testing would be nice, but I am not sure that we can guarantee that
+  jpeg or png files are binary identical on each run across different computers.
+  But if the number of false positives is small, it would certainly be a useful
+  addition.
+
+
+Imagecache Actions 7.x-1.3
+--------------------------
+Targeted release date: ...
+
+- Continue to keep the D7 issue queue clean.
+- Check help and documentation. a.o: hook_help, effect descriptions.
+- Improve Imagemagick support and/or document what effects are not working for
+  which toolkit (version).
+- Add testing. The idea is to create a set of image styles that cover all
+  effects and can be used to visually check for regressions.
+
+  Automated testing would be nice, but I am not sure that we can guarantee that
+  jpeg or png files are binary identical on each run across different computers.
+  But if the number of false positives is small, it would certainly be a useful
+  addition.
+- Refactor code:
+  - Extract common form fields.
+  - Extract common error handling.
+  - (STARTED) Clean up comments, todo's, etc.
+  - (STARTED) Doxygen code documentation according to latest standards
+  - Increase the amount of lazy loaded code.
+
+
+Imagecache Actions 7.x-1.5
+--------------------------
+Targeted release date: ...
+
+- Look at outstanding feature requests
+- Continue to keep the D7 issue queue clean.
+- Keep improving Imagemagick support, a.o:
+  - Try to get insight into what version of imagemagick is required by what
+    effect.
+  - Document which effects might produce different results.
+- Continue refactoring code:
+  - Extract common form fields.
+  - Extract common error handling.
+  - (STARTED) Clean up comments, todo's, etc.
+  - (STARTED) Doxygen code documentation according to latest standards.
+  - Increase the amount of lazy loaded code.
+
+
+Imagecache Actions 8.x-2.x
+--------------------------
+Targeted release date: ...
+
+- Convert image effects into plugins (as [#1821854] does for core).
+- This will make adding new effects much simpler, so we can easier add them.
+- Should we rename the module to image_effects?
+- We should strive to merge with other modules that provide image effects:
+  - FiltersIE module (https://drupal.org/project/filtersie)
+  - Imagecache Effects: https://drupal.org/project/imagecache_effects (D6 only,
+    but are their effects more advanced then our counterparts or do they add new
+    effects?)
+  - Image watermark: https://drupal.org/project/watermark (D5 only, but is their
+    watermark effect more advanced?)
+  - ImageCache Scale-9 Actions: https://drupal.org/project/imagecache_scale9actions
+  - ImageEffects: https://drupal.org/project/imageeffects (pixelate and flip).
+  - Imagick: https://www.drupal.org/project/imagick
+  - etc.

+ 13 - 0
sites/all/modules/contrib/files/imagecache_actions/autorotate/imagecache_autorotate.info

@@ -0,0 +1,13 @@
+name = Imagecache Autorotate
+description = Provides an image effect to autorotate an image based on EXIF data.
+package = Media
+core = 7.x
+
+dependencies[] = image
+
+; Information added by Drupal.org packaging script on 2016-02-19
+version = "7.x-1.7"
+core = "7.x"
+project = "imagecache_actions"
+datestamp = "1455872655"
+

+ 25 - 0
sites/all/modules/contrib/files/imagecache_actions/autorotate/imagecache_autorotate.install

@@ -0,0 +1,25 @@
+<?php
+/**
+ * Implements hook_requirements().
+ */
+function imagecache_autorotate_requirements($phase) {
+  $result = array();
+  $t = get_t();
+  if (!extension_loaded('exif')) {
+    $result['imagecache_autorotate_exif_extension'] = array(
+      'title'=> 'EXIF extension',
+      'value'=> $phase === 'runtime' ? $t('Disabled') : '',
+      'description'=> $t('The autorotate image effect requires the exif extension to be enabled.'),
+      'severity' => REQUIREMENT_ERROR,
+    );
+  }
+  else {
+    $result['imagecache_autorotate_exif_extension'] = array(
+      'title'=> 'EXIF extension',
+      'value'=> $t('Enabled'),
+      'severity' => REQUIREMENT_OK,
+    );
+
+  }
+  return $result;
+}

+ 235 - 0
sites/all/modules/contrib/files/imagecache_actions/autorotate/imagecache_autorotate.module

@@ -0,0 +1,235 @@
+<?php
+/**
+ * @file Autorotate image based on EXIF Orientation tag.
+ *
+ * EXIF: https://en.wikipedia.org/wiki/Exchangeable_image_file_format
+ * EXIF orientation tag: http://sylvana.net/jpegcrop/exif_orientation.html
+ *
+ * Originally contributed by jonathan_hunt https://drupal.org/user/28976,
+ * September 1, 2009
+ */
+
+/**
+ * Implements hook_image_effect_info().
+ *
+ * Defines information about the supported effects.
+ */
+function imagecache_autorotate_image_effect_info() {
+  $effects = array();
+
+  $effects['imagecache_autorotate'] = array(
+    'label' => t('Autorotate'),
+    'help' => t('Autorotate image based on EXIF orientation and reset that tag.'),
+    'effect callback' => 'imagecache_autorotate_effect',
+    'dimensions callback' => 'imagecache_autorotate_dimensions',
+    'form callback' => 'imagecache_autorotate_form',
+    'summary theme' => 'imagecache_autorotate_summary',
+  );
+
+  return $effects;
+}
+
+/**
+ * Implements hook_theme().
+ *
+ * Registers theme functions for the effect summaries.
+ */
+function imagecache_autorotate_theme() {
+  return array(
+    'imagecache_autorotate_summary' => array(
+      'variables' => array('data' => NULL),
+    ),
+  );
+}
+
+/**
+ * Builds the auto-rotate form.
+ *
+ * This effect has no options, only some help text, so the form is displayed
+ * anyway.
+ */
+function imagecache_autorotate_form() {
+  $form = array();
+  $form['help'] = array(
+    '#markup' => "<p><strong>There are no user-configurable options for this process.</strong></p>
+      <p>Certain cameras can embed <em>orientation</em> information into image
+      files when they save them. This information is embedded in an EXIF tag
+      and can be used to rotate images to their correct position for display.
+      <em>Not all cameras or images contain this information.</em>
+      This process is only useful for images that contain this information,
+      whereas for other images it is harmless.
+      </p>
+      <p>Although most modern browsers do support the orientation tag, the
+      information may get lost or become incorrect by other operations.
+      So, to support all browsers and prevent rotation errors, it is better to
+      start each image style with this effect.
+      </p>
+      <p>The expected/supported values are:<br/>
+      <strong>Tag</strong>: <code>0x0112  Orientation</code>
+      </p>
+      <ul>
+      <li>1 = Horizontal (normal)</li>
+      <li>3 = Rotate 180</li>
+      <li>6 = Rotate 90 CW</li>
+      <li>8 = Rotate 270 CW</li>
+      </ul>
+      <p>Wikipedia: <a href='https://en.wikipedia.org/wiki/Exchangeable_image_file_format'>Exchangeable image file format</a></p>
+    ",
+  );
+  return $form;
+}
+
+/**
+ * Implements theme_hook() for the autorotate effect summary.
+ *
+ * param array $variables
+ *   An associative array containing:
+ *   - data: The current configuration for this image effect.
+ *
+ * @return string
+ *   The HTML for the summary of this image effect.
+ * @ingroup themeable
+ */
+function theme_imagecache_autorotate_summary(/*array $variables*/) {
+  return 'image based on its EXIF data.';
+}
+
+/**
+ * Autorotate image based on EXIF Orientation tag.
+ */
+function imagecache_autorotate_effect(stdClass $image /*, $data*/) {
+  // Test to see if EXIF is supported by the current image type.
+  if (in_array($image->info['mime_type'], array('image/jpeg', 'image/tiff'))) {
+    // Hand over to toolkit.
+    return image_toolkit_invoke('imagecache_autorotate', $image);
+  }
+  else if ($image->source === 'modules/image/sample.png' && user_access('administer image styles')) {
+    if (!extension_loaded('exif')) {
+      // Issue a warning if we are in the admin screen and the exif extension is
+      // not enabled.
+      drupal_set_message(t('The autorotate image effect requires the exif extension to be enabled.'), 'warning');
+      if ($image->toolkit === 'imagemagick') {
+        drupal_set_message(t('Though imagemagick will work without the exif extension, subsequent effects may fail as the image dimensions cannot be updated.'), 'warning');
+      }
+    }
+  }
+  return TRUE;
+}
+
+/**
+ * GD toolkit specific implementation of this image effect.
+ *
+ * @param stdClass $image
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function image_gd_imagecache_autorotate(stdClass $image) {
+  if (!function_exists('exif_read_data')) {
+    watchdog('imagecache_actions', 'Image %file could not be auto-rotated: !message', array('%file' => $image->source, '!message' => t('The exif_read_data() function is not available in this PHP installation. You probably have to enable the exif extension.')));
+    return FALSE;
+  }
+  $exif = exif_read_data(drupal_realpath($image->source));
+  if (isset($exif['Orientation'])) {
+    // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/EXIF.html:
+    // 1 = Horizontal (normal)
+    // 2 = Mirror horizontal
+    // 3 = Rotate 180
+    // 4 = Mirror vertical
+    // 5 = Mirror horizontal and rotate 270 CW
+    // 6 = Rotate 90 CW
+    // 7 = Mirror horizontal and rotate 90 CW
+    // 8 = Rotate 270 CW
+    // @todo: Add horizontal and vertical flips etc.
+    // imagecopy seems to be able to mirror, see conmments on
+    // http://php.net/manual/en/function.imagecopy.php
+    // @todo: Create sample set for tests.
+    switch ($exif['Orientation']) {
+      case 3:
+        $degrees = 180;
+        break;
+      case 6:
+        $degrees = 90;
+        break;
+      case 8:
+        $degrees = 270;
+        break;
+      default:
+        $degrees = 0;
+    }
+    if ($degrees != 0) {
+      return image_rotate($image, $degrees);
+    }
+  }
+  return TRUE;
+}
+
+/**
+ * Imagemagick toolkit specific implementation of this image effect.
+ *
+ * @param stdClass $image
+ *   An image object.
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ *
+ * @see http://www.imagemagick.org/script/command-line-options.php#auto-orient
+ */
+function image_imagemagick_imagecache_autorotate(stdClass $image) {
+  // Use the exif extension, if enabled, to figure out the new dimensions.
+  // Moreover (see [#2366163]): to prevent a bug in IM to incorrectly rotate the
+  // image when it should not, we only pass the auto-orient argument when the
+  // exif extension could detect the 'Orientation' tag.
+  if (function_exists('exif_read_data')) {
+    $exif = exif_read_data(drupal_realpath($image->source));
+    if (isset($exif['Orientation'])) {
+      switch ($exif['Orientation']) {
+        case 1:
+          // Normal orientation: no need to rotate or to change the dimensions.
+          break;
+        case 5:
+        case 6:
+        case 7:
+        case 8:
+          // 90 or 270 degrees rotation (+ optional mirror): swap dimensions.
+          $image->ops[] = '-auto-orient';
+          $tmp = $image->info['width'];
+          $image->info['width'] = $image->info['height'];
+          $image->info['height'] = $tmp;
+          break;
+        default:
+          // All other orientations: pass the arguments, but the dimensions
+          // remain the same.
+          $image->ops[] = '-auto-orient';
+          break;
+      }
+    }
+  }
+  else {
+    // We do add the auto-orient argument to IM. IM will determine itself
+    // whether to rotate or not.
+    $image->ops[] = '-auto-orient';
+    // However we cannot keep track of the dimensions anymore.
+    $image->info['width'] = $image->info['height'] = NULL;
+  }
+  return TRUE;
+}
+
+/**
+ * Image dimensions callback for this image effect.
+ *
+ * @param array $dimensions
+ *   An array with the dimensions (in pixels) to be modified.
+ * param array $data
+ *   An associative array containing the effect data.
+ */
+function imagecache_autorotate_dimensions(array &$dimensions/*, array $data*/) {
+  // We can only know the resulting dimensions if both dimensions are equal.
+  // Otherwise we need to inspect the image itself, which is not passed in here.
+  // (this callback was introduced to enhance performance by NOT accessing the
+  // image file when rendering the width and height attributes of the html img
+  // tag).
+  if ($dimensions['width'] !== $dimensions['height']) {
+    $dimensions['width'] = $dimensions['height'] = NULL;
+  }
+}

BIN
sites/all/modules/contrib/files/imagecache_actions/autorotate/portrait-painting.jpg


+ 1249 - 0
sites/all/modules/contrib/files/imagecache_actions/canvasactions/canvasactions.inc

@@ -0,0 +1,1249 @@
+<?php
+/**
+ * @file Helper functions for the canvas actions for imagecache
+ *
+ * @author Dan Morrison http://coders.co.nz
+ *
+ * Individually configurable rounded corners logic contributed by canaryMason
+ * 2009 03 https://drupal.org/node/402112
+ *
+ * Better algorithm for trimming rounded corners from donquixote
+ * 2009 09 https://drupal.org/node/564036
+ *
+ */
+
+if (!function_exists('image_overlay')) {
+  module_load_include('inc', 'imagecache_actions', 'image_overlay');
+}
+if (!function_exists('imagecache_actions_pos_form')) {
+  module_load_include('inc', 'imagecache_actions', 'utility-form');
+}
+if (!function_exists('imagecache_actions_keyword_filter')) {
+  module_load_include('inc', 'imagecache_actions', 'utility');
+}
+
+/**
+ * Image effect form callback for the image mask effect.
+ *
+ * @param array $data
+ *   The current configuration for this image effect.
+ *
+ * @return array
+ *   The form definition for this effect.
+ */
+function canvasactions_imagemask_form(array $data) {
+  // @todo: add offset/positioning/scaling support - currently the mask is applied to the supplied image without resizing and positioned at (0,0)
+  $form = array();
+  $form['effect_help_text'] = array(
+    '#type' => 'item',
+    '#title' => t('Image mask'),
+    '#description' => t('This effect will add (or replace) a transparency channel to your image. The mask file should be a grayscale image where black is fully transparent and white is fully opaque. The referenced mask will be applied to the top left of the image.'),
+  );
+  $form['path'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Mask file name'),
+    '#default_value' => isset($data['path']) ? $data['path'] : '',
+    '#description' => imagecache_actions_file_field_description(),
+    '#element_validate' => array('imagecache_actions_validate_file'),
+  );
+  return $form;
+}
+
+/**
+ * Implements theme_hook() for the image mask effect summary.
+ *
+ * @param array $variables
+ *   An associative array containing:
+ *   - data: The current configuration for this image effect.
+ *
+ * @return string
+ *   The HTML for the summary of this image effect.
+ * @ingroup themeable
+ */
+function theme_canvasactions_imagemask_summary(array $variables) {
+  $data = $variables['data'];
+  return 'file: ' . $data['path'];
+}
+
+/**
+ * Image effect callback for the image mask effect.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function canvasactions_imagemask_effect(stdClass $image, array $data) {
+  $mask = imagecache_actions_image_load($data['path'], $image->toolkit);
+  if ($mask) {
+    // @todo: (sydneyshan) Consider best way to add offset support - I assume we
+    // would position the mask somewhere (top/left/offset px etc) and choose if
+    // the surrounding area is white or black (opaque or transparent) using an
+    // extra form element (radio). Assess existing positioning code first to
+    // reduce duplication of code. Pass the results to the following function as
+    // array($mask, $data). Perhaps add a 'scale mask to fit image'/'scale image
+    // to fit mask'/'no scale' radio group?
+    return image_toolkit_invoke('imagemask', $image, array($mask));
+  }
+  return FALSE;
+}
+
+/**
+ * GD toolkit specific implementation of the image mask effect.
+ *
+ * @param stdClass $image
+ *   Image object containing the GD image resource to operate on.
+ * @param stdClass $mask
+ *   An image object containing the image to use as mask.
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function image_gd_imagemask(stdClass $image, stdClass $mask) {
+  $newPicture = imagecreatetruecolor($image->info['width'], $image->info['height']);
+  imagesavealpha($newPicture, TRUE);
+  imagealphablending($newPicture, TRUE);
+  $transparent = imagecolorallocatealpha($newPicture, 0, 0, 0, 127);
+  imagefill($newPicture, 0, 0, $transparent);
+
+  // Perform pixel-based alpha map application.
+  for ($x = 0; $x < $image->info['width']; $x++) {
+    for ($y = 0; $y < $image->info['height']; $y++) {
+      // Deal with images with mismatched sizes
+      if ($x >= $mask->info['width'] || $y >= $mask->info['height']) {
+        imagesetpixel($newPicture, $x, $y, $transparent);
+      }
+      else {
+        $alpha = imagecolorsforindex($mask->resource, imagecolorat($mask->resource, $x, $y));
+        $alpha = 127 - floor($alpha['red'] / 2);
+        $color = imagecolorsforindex($image->resource, imagecolorat($image->resource, $x, $y));
+        imagesetpixel($newPicture, $x, $y, imagecolorallocatealpha($newPicture, $color['red'], $color['green'], $color['blue'], $alpha));
+      }
+    }
+  }
+
+  // Copy back to original picture.
+  imagedestroy($image->resource);
+  $image->resource = $newPicture;
+
+  return TRUE;
+}
+
+
+/**
+ * Imagemagick toolkit specific implementation of the image mask effect.
+ *
+ * @param stdClass $image
+ *   Image object containing the image resource to operate on.
+ * @param stdClass $mask
+ *   An image object containing the image to use as mask.
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function image_imagemagick_imagemask(stdClass $image, stdClass $mask) {
+  $image->ops[] = escapeshellarg($mask->source);
+  $image->ops[] = '-alpha Off -compose CopyOpacity -composite';
+  return TRUE;
+}
+
+/**
+ * Image effect form callback for the define canvas effect.
+ *
+ * @param array $data
+ *   The current configuration for this image effect.
+ *
+ * @return array
+ *   The form definition for this effect.
+ */
+function canvasactions_definecanvas_form(array $data) {
+  module_load_include('inc', 'imagecache_actions', 'utility-color');
+  $defaults = array(
+    'RGB' => array(
+      'HEX' => '#333333',
+    ),
+    'under' => TRUE,
+    'exact' => array(
+      'width' => '',
+      'height' => '',
+      'xpos' => 'center',
+      'ypos' => 'center',
+    ),
+    'relative' => array(
+      'leftdiff' => '',
+      'rightdiff' => '',
+      'topdiff' => '',
+      'bottomdiff' => '',
+    ),
+  );
+  $data += $defaults;
+
+  $form = array(
+    'RGB' => imagecache_rgb_form($data['RGB']),
+    'help' => array(
+      '#markup' => t('Enter no color value for transparent. This will have the effect of adding clear margins around the image.'),
+      '#prefix' => '<p>',
+      '#suffix' => '</p>',
+    ),
+    'under' => array(
+      '#type' => 'checkbox',
+      '#title' => t('Resize canvas <em>under</em> image (possibly cropping)'),
+      '#default_value' => $data['under'],
+      '#description' => t('If <em>not</em> set, this will create a solid flat layer, probably totally obscuring the source image'),
+    ),
+  );
+  $form['info'] = array('#value' => t('Enter values in ONLY ONE of the below options. Either exact or relative. Most values are optional - you can adjust only one dimension as needed. If no useful values are set, the current base image size will be used.'));
+  $form['exact'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#title' => 'Exact size',
+    'help' => array(
+      '#markup' => t('Set the canvas to a precise size, possibly cropping the image. Use to start with a known size.'),
+      '#prefix' => '<p>',
+      '#suffix' => '</p>',
+    ),
+    'width' => array(
+      '#type' => 'textfield',
+      '#title' => t('Width'),
+      '#default_value' => $data['exact']['width'],
+      '#description' => t('Enter a value in pixels or percent'),
+      '#size' => 5,
+    ),
+    'height' => array(
+      '#type' => 'textfield',
+      '#title' => t('Height'),
+      '#default_value' => $data['exact']['height'],
+      '#description' => t('Enter a value in pixels or percent'),
+      '#size' => 5,
+    ),
+  );
+  $form['exact'] = array_merge($form['exact'], imagecache_actions_pos_form($data['exact']));
+  if (!$data['exact']['width'] && !$data['exact']['height']) {
+    $form['exact']['#collapsed'] = TRUE;
+  }
+
+  $form['relative'] = array(
+    '#type' => 'fieldset',
+    '#collapsible' => TRUE,
+    '#title' => t('Relative size'),
+    'help' => array(
+      '#markup' => t('Set the canvas to a relative size, based on the current image dimensions. Use to add simple borders or expand by a fixed amount. Negative values may crop the image.'),
+      '#prefix' => '<p>',
+      '#suffix' => '</p>',
+    ),
+    'leftdiff' => array(
+      '#type' => 'textfield',
+      '#title' => t('left difference'),
+      '#default_value' => $data['relative']['leftdiff'],
+      '#size' => 6,
+      '#description' => t('Enter an offset in pixels.'),
+    ),
+    'rightdiff' => array(
+      '#type' => 'textfield',
+      '#title' => t('right difference'),
+      '#default_value' => $data['relative']['rightdiff'],
+      '#size' => 6,
+      '#description' => t('Enter an offset in pixels.'),
+    ),
+    'topdiff' => array(
+      '#type' => 'textfield',
+      '#title' => t('top difference'),
+      '#default_value' => $data['relative']['topdiff'],
+      '#size' => 6,
+      '#description' => t('Enter an offset in pixels.'),
+    ),
+    'bottomdiff' => array(
+      '#type' => 'textfield',
+      '#title' => t('bottom difference'),
+      '#default_value' => $data['relative']['bottomdiff'],
+      '#size' => 6,
+      '#description' => t('Enter an offset in pixels.'),
+    ),
+  );
+  if (!$data['relative']['leftdiff'] && !$data['relative']['rightdiff'] && !$data['relative']['topdiff'] && !$data['relative']['bottomdiff']) {
+    $form['relative']['#collapsed'] = TRUE;
+  }
+
+  $form['#submit'][] = 'canvasactions_definecanvas_form_submit';
+  return $form;
+}
+
+/**
+ * Implements theme_hook() for the define canvas effect summary.
+ *
+ * @param array $variables
+ *   An associative array containing:
+ *   - data: The current configuration for this image effect.
+ *
+ * @return string
+ *   The HTML for the summary of this image effect.
+ * @ingroup themeable
+ */
+function theme_canvasactions_definecanvas_summary(array $variables) {
+  $data = $variables['data'];
+  if ($data['exact']['width'] || $data['exact']['height']) {
+    $w = !empty($data['exact']['width']) ? $data['exact']['width'] : '100%';
+    $h = !empty($data['exact']['height']) ? $data['exact']['height'] : '100%';
+    $x = !empty($data['exact']['xpos']) ? $data['exact']['xpos'] : '0';
+    $y = !empty($data['exact']['ypos']) ? $data['exact']['ypos'] : '0';
+    $output = "{$w}x{$h} ($x, $y)";
+  }
+  else {
+    $output = ' left:' . $data['relative']['leftdiff'];
+    $output .= ' right:' . $data['relative']['rightdiff'];
+    $output .= ' top:' . $data['relative']['topdiff'];
+    $output .= ' bottom:' . $data['relative']['bottomdiff'];
+  }
+  $output .= theme('imagecacheactions_rgb', array('RGB' => $data['RGB']));
+  $output .= ($data['under']) ? t(" <b>under</b> image ") : t(" <b>over</b> image ");
+  return $output;
+}
+
+/**
+ * Image effect callback for the define canvas effect.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *
+ * @return boolean
+ *   true on success, false otherwise.
+ */
+function canvasactions_definecanvas_effect(stdClass $image, array $data) {
+  // May be given either exact or relative dimensions.
+  if ($data['exact']['width'] || $data['exact']['height']) {
+    // Allows only one dimension to be used if the other is unset.
+    if (!$data['exact']['width']) {
+      $data['exact']['width'] = $image->info['width'];
+    }
+    if (!$data['exact']['height']) {
+      $data['exact']['height'] = $image->info['height'];
+    }
+
+    $targetsize['width'] = imagecache_actions_percent_filter($data['exact']['width'], $image->info['width']);
+    $targetsize['height'] = imagecache_actions_percent_filter($data['exact']['height'], $image->info['height']);
+
+    $targetsize['left'] = image_filter_keyword($data['exact']['xpos'], $targetsize['width'], $image->info['width']);
+    $targetsize['top'] = image_filter_keyword($data['exact']['ypos'], $targetsize['height'], $image->info['height']);
+
+  }
+  else {
+    // Calculate relative size.
+    $targetsize['width'] = $image->info['width'] + $data['relative']['leftdiff'] + $data['relative']['rightdiff'];
+    $targetsize['height'] = $image->info['height'] + $data['relative']['topdiff'] + $data['relative']['bottomdiff'];
+    $targetsize['left'] = $data['relative']['leftdiff'];
+    $targetsize['top'] = $data['relative']['topdiff'];
+  }
+
+  // Convert from hex (as it is stored in the UI).
+  if ($data['RGB']['HEX'] && $deduced = imagecache_actions_hex2rgba($data['RGB']['HEX'])) {
+    $data['RGB'] = array_merge($data['RGB'], $deduced);
+  }
+
+  // All the math is done, now defer to the toolkit in use.
+  $data['targetsize'] = $targetsize;
+
+  $success = image_toolkit_invoke('definecanvas', $image, array($data));
+  if ($success) {
+    $image->info['width'] = $targetsize['width'];
+    $image->info['height'] = $targetsize['height'];
+  }
+  return $success;
+}
+
+/**
+ * GD toolkit specific implementation of the define canvas effect.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *   The parameters for this effect. $data['targetsize'] is an array expected to
+ *   contain a width, height and a left, top.
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function image_gd_definecanvas(stdClass $image, array $data) {
+  $targetsize = $data['targetsize'];
+  $RGB = $data['RGB'];
+
+  $newcanvas = imagecreatetruecolor($targetsize['width'], $targetsize['height']);
+  imagesavealpha($newcanvas, TRUE);
+  imagealphablending($newcanvas, FALSE);
+  imagesavealpha($image->resource, TRUE);
+  if ($RGB['HEX']) {
+    // Set color, allow it to define transparency, or assume opaque.
+    $background = imagecolorallocatealpha($newcanvas, $RGB['red'], $RGB['green'], $RGB['blue'], $RGB['alpha']);
+  }
+  else {
+    // No color, attempt transparency, assume white.
+    $background = imagecolorallocatealpha($newcanvas, 255, 255, 255, 127);
+  }
+  imagefilledrectangle($newcanvas, 0, 0, $targetsize['width'], $targetsize['height'], $background);
+
+  if ($data['under']) {
+    $canvas_object = new stdClass();
+    $canvas_object->resource = $newcanvas;
+    $canvas_object->info = array(
+        'width' => $targetsize['width'],
+        'height' => $targetsize['height'],
+        'mime_type' => $image->info['mime_type'],
+        'extension' => $image->info['extension'],
+      );
+    $canvas_object->toolkit = $image->toolkit;
+    image_overlay($image, $canvas_object, $targetsize['left'], $targetsize['top'], 100, TRUE);
+  }
+  else {
+    $image->resource = $newcanvas;
+  }
+  return TRUE;
+}
+
+/**
+ * Imagemagick toolkit specific implementation of the define canvas effect.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *   The parameters for this effect. $data['targetsize'] is an array expected to
+ *   contain a width, height and a left, top.
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ *
+ * @see http://www.imagemagick.org/script/command-line-options.php#extent
+ */
+function image_imagemagick_definecanvas(stdClass $image, $data) {
+  // Reset any gravity settings from earlier effects.
+  $image->ops[] = '-gravity None';
+
+  $backgroundcolor = $data['RGB']['HEX'] != '' ? '#' . ltrim($data['RGB']['HEX'], '#') : 'None';
+  $image->ops[] = '-background ' . escapeshellarg($backgroundcolor);
+
+  $compose_operator = $data['under'] ? 'src-over' : 'dst-over';
+  $image->ops[] = "-compose $compose_operator";
+
+  $targetsize = $data['targetsize'];
+  $geometry = sprintf('%dx%d', $targetsize['width'], $targetsize['height']);
+  if ($targetsize['left'] || $targetsize['top']) {
+    $geometry .= sprintf('%+d%+d', -$targetsize['left'], -$targetsize['top']);
+  }
+  $image->ops[] = '-extent ' . escapeshellarg($geometry);
+
+  return TRUE;
+}
+
+/**
+ * Image dimensions callback for the define canvas effect.
+ *
+ * @param array $dimensions
+ *   Dimensions to be modified - an associative array containing the items
+ *   'width' and 'height' (in pixels).
+ * @param array $data
+ *   An associative array containing the effect data.
+ */
+function canvasactions_definecanvas_dimensions(array &$dimensions, array $data) {
+  // May be given either exact or relative dimensions.
+  if ($data['exact']['width'] || $data['exact']['height']) {
+    // Allows only one dimension to be used if the other is unset.
+    if (!$data['exact']['width']) {
+      $data['exact']['width'] = $dimensions['width'];
+    }
+    if (!$data['exact']['height']) {
+      $data['exact']['height'] = $dimensions['height'];
+    }
+
+    $dimensions['width'] = imagecache_actions_percent_filter($data['exact']['width'], $dimensions['width']);
+    $dimensions['height'] = imagecache_actions_percent_filter($data['exact']['height'], $dimensions['height']);
+  }
+  else {
+    // Calculate relative sizes (only possible if we have the current size).
+    if ($dimensions['width'] !== NULL) {
+      $dimensions['width'] = $dimensions['width'] + (int) $data['relative']['leftdiff'] + (int) $data['relative']['rightdiff'];
+    }
+    if ($dimensions['height'] !== NULL) {
+      $dimensions['height'] = $dimensions['height'] + (int) $data['relative']['topdiff'] + (int) $data['relative']['bottomdiff'];
+    }
+  }
+}
+
+
+/**
+ * Image effect form callback for the underlay (background) effect.
+ *
+ * @param array $data
+ *   The current configuration for this image effect.
+ *
+ * @return array
+ *   The form definition for this effect.
+ */
+function canvasactions_canvas2file_form(array $data) {
+  $defaults = array(
+    'xpos' => '0',
+    'ypos' => '0',
+    'alpha' => '100',
+    'path' => '',
+    'dimensions' => 'original',
+  );
+  $data = array_merge($defaults, (array) $data);
+
+  $form = imagecache_actions_pos_form($data);
+  $form['alpha'] = array(
+    '#type' => 'textfield',
+    '#title' => t('opacity'),
+    '#default_value' => $data['alpha'],
+    '#size' => 6,
+    '#description' => t('Opacity: 0-100. Be aware that values other than 100% may be slow to process.'),
+  );
+  $form['path'] = array(
+    '#type' => 'textfield',
+    '#title' => t('file name'),
+    '#default_value' => $data['path'],
+    '#description' => imagecache_actions_file_field_description(),
+    '#element_validate' => array('imagecache_actions_validate_file'),
+  );
+  $form['dimensions'] = array(
+    '#type' => 'radios',
+    '#title' => t('final dimensions'),
+    '#default_value' => $data['dimensions'],
+    '#options' => array(
+      'original' => 'original (dimensions are retained)',
+      'background' => 'background (image will be forced to match the size of the background)',
+      'minimum' => 'minimum (image may be cropped)',
+      'maximum' => 'maximum (image may end up with gaps)',
+    ),
+    '#description' => t('What to do when the background image is a different size from the source image. Backgrounds are not tiled, but may be arbitrarily large.'),
+  );
+  return $form;
+}
+
+/**
+ * Implements theme_hook() for the underlay (background) effect summary.
+ *
+ * @param array $variables
+ *   An associative array containing:
+ *   - data: The current configuration for this image effect.
+ *
+ * @return string
+ *   The HTML for the summary of this image effect.
+ * @ingroup themeable
+ */
+function theme_canvasactions_canvas2file_summary($variables) {
+  $data = $variables['data'];
+  $file = $data['path'];
+  return "xpos:{$data['xpos']} , ypos:{$data['ypos']} alpha:{$data['alpha']}%. file: $file, dimensions:{$data['dimensions']}";
+}
+
+/**
+ * Image effect callback for the underlay (background) effect.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *
+ * @return boolean
+ *   true on success, false otherwise.
+ */
+function canvasactions_canvas2file_effect(stdClass $image, array $data) {
+  $underlay = imagecache_actions_image_load($data['path'], $image->toolkit);
+  if ($underlay) {
+    // To handle odd sizes, we will resize/crop the background image to the
+    // desired dimensions before starting the merge. The built-in
+    // imagecopymerge, and the watermark library both do not allow overlays to
+    // be bigger than the target.
+
+    // Adjust size.
+    $crop_rules = array(
+      'xoffset' => 0,
+      'yoffset' => 0,
+    );
+    if (empty($data['dimensions'])) {
+      $data['dimensions'] = 'original';
+    }
+    switch ($data['dimensions']) {
+      case 'original':
+        // If the underlay is smaller than the target size,
+        // then when preparing the underlay by cropping it,
+        // the offsets may need to be negative
+        // which will produce a 'cropped' image larger than the original.
+        // In this case, we need to calculate the position of the bg image
+        // in relation to the space it will occupy under the top layer
+        //$crop_rules['xoffset'] = $underlay->info['width'] - $image->info['width'] ;
+
+        $crop_rules['width'] = $image->info['width'];
+        $crop_rules['height'] = $image->info['height'];
+        break;
+      case 'background':
+        $crop_rules['width'] = $underlay->info['width'];
+        $crop_rules['height'] = $underlay->info['height'];
+        break;
+      case 'minimum':
+        $crop_rules['width'] = min($underlay->info['width'], $image->info['width']);
+        $crop_rules['height'] = min($underlay->info['height'], $image->info['height']);
+        break;
+      case 'maximum':
+        $crop_rules['width'] = max($underlay->info['width'], $image->info['width']);
+        $crop_rules['height'] = max($underlay->info['height'], $image->info['height']);
+        break;
+    }
+    // imageapi crop assumes upsize is legal.
+
+    // Crop both before processing to avoid unwanted processing.
+    image_crop_effect($underlay, $crop_rules);
+    // @todo: BUG - this doesn't position either
+    // Actually this fails because imagecache_crop fills it with solid color when 'cropping' to a larger size.
+    //imagecache_crop_image($image, $crop_rules);
+    //dpm(get_defined_vars());
+    // This func modifies the underlay image by ref, placing the current canvas on it.
+    if (image_overlay($image, $underlay, $data['xpos'], $data['ypos'], $data['alpha'], TRUE)) {
+      //$image->resource = $underlay->resource;
+      $image = $underlay; //@todo: this is a no-op.
+      return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+/**
+ * Image dimensions callback for the underlay (background) effect.
+ *
+ * @param array $dimensions
+ *   Dimensions to be modified - an associative array containing the items
+ *   'width' and 'height' (in pixels).
+ * @param array $data
+ *   An associative array containing the effect data.
+ */
+function canvasactions_canvas2file_dimensions(array &$dimensions, array $data) {
+  if ($data['dimensions'] !== 'original') {
+    $underlay = imagecache_actions_image_load($data['path']);
+    if ($underlay) {
+      // If the new dimensions are taken from the background, we don't need to
+      // know the original dimensions, we can just set the new dimensions to the
+      // dimensions of the background. Otherwise, we need to know the old
+      // dimensions. If unknown we have to leave them unknown.
+      switch ($data['dimensions']) {
+        case 'background':
+          $dimensions['width'] = $underlay->info['width'];
+          $dimensions['height'] = $underlay->info['height'];
+          break;
+        case 'minimum':
+          if ($dimensions['width'] !== NULL) {
+            $dimensions['width'] = min($underlay->info['width'], $dimensions['width']);
+          }
+          if ($dimensions['height'] !== NULL) {
+            $dimensions['height'] = min($underlay->info['height'], $dimensions['height']);
+          }
+          break;
+        case 'maximum':
+          if ($dimensions['width'] !== NULL) {
+            $dimensions['width'] =  max($underlay->info['width'], $dimensions['width']);
+          }
+          if ($dimensions['height'] !== NULL) {
+            $dimensions['height'] = max($underlay->info['height'], $dimensions['height']);
+          }
+      break;
+      }
+    }
+  }
+}
+
+
+/**
+ * Image effect form callback for the overlay (watermark) effect.
+ *
+ * @param array $data
+ *   The current configuration for this image effect.
+ *
+ * @return array
+ *   The form definition for this effect.
+ */
+function canvasactions_file2canvas_form(array $data) {
+
+  $defaults = array(
+    'xpos' => '',
+    'ypos' => '',
+    'alpha' => '100',
+    'scale' => '',
+    'path' => '',
+  );
+  $data = array_merge($defaults, (array) $data);
+
+  $form = array(
+    'help' => array(
+      '#markup' => t('Note that using a non transparent overlay that is larger than the source image may result in unwanted results - a solid background.'),
+    ),
+  );
+  $form += imagecache_actions_pos_form($data);
+  $form['alpha'] = array(
+    '#type' => 'textfield',
+    '#title' => t('opacity'),
+    '#default_value' => $data['alpha'],
+    '#field_suffix' => t('%'),
+    '#size' => 6,
+    '#description' => t('Opacity: 0-100. <b>Warning:</b> Due to a limitation in the GD toolkit, using an opacity other than 100% requires the system to use an algorithm that\'s much slower than the built-in functions. If you want partial transparency, you are better to use an already-transparent png as the overlay source image.'),
+    '#element_validate' => array('imagecache_actions_validate_number_non_negative'),
+  );
+  $form['scale'] = array(
+    '#type' => 'textfield',
+    '#title' => t('scale'),
+    '#default_value' => $data['scale'],
+    '#field_suffix' => t('%'),
+    '#size' => 6,
+    '#description' => t('Scales the overlay with respect to the source, thus not its own dimensions. Leave empty to use the original size of overlay image.'),
+    '#element_validate' => array('imagecache_actions_validate_number_positive'),
+  );
+  $form['path'] = array(
+    '#type' => 'textfield',
+    '#title' => t('file name'),
+    '#default_value' => $data['path'],
+    '#description' => imagecache_actions_file_field_description(),
+    '#element_validate' => array('imagecache_actions_validate_file'),
+  );
+  return $form;
+}
+
+/**
+ * Implements theme_hook() for the overlay (watermark) effect summary.
+ *
+ * @param array $variables
+ *   An associative array containing:
+ *   - data: The current configuration for this image effect.
+ *
+ * @return string
+ *   The HTML for the summary of this image effect.
+ * @ingroup themeable
+ */
+function theme_canvasactions_file2canvas_summary(array $variables) {
+  $data = $variables['data'];
+  return '<strong>' . $data['path'] . '</strong>, x:' . $data['xpos'] . ', y:' . $data['ypos'] . ', alpha:' . (!empty($data['alpha']) ? $data['alpha'] : 100) . '%' . ', scale:' . (!empty($data['scale']) ? $data['scale'].'%' : '-');
+}
+
+/**
+ * Image effect callback for the overlay (watermark) image effect.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *
+ * @return boolean
+ *   true on success, false otherwise.
+ */
+function canvasactions_file2canvas_effect(stdClass $image, array $data) {
+  $overlay = imagecache_actions_image_load($data['path']);
+  if ($overlay) {
+    if (!empty($data['scale']) && $data['scale'] > 0) {
+      // Scale the overlay with respect to the dimensions of the source being
+      // overlaid. To maintain the aspect ratio, only the width of the overlay
+      // is scaled like that, the height of the overlay follows the aspect
+      // ratio (that is why we use image_scale instead of image_resize).
+      $overlay_w = $image->info['width'] * $data['scale'] / 100;
+      image_scale($overlay, $overlay_w, NULL, TRUE);
+    }
+    if (!isset($data['alpha'])) {
+      $data['alpha'] = 100;
+    }
+    return image_overlay($image, $overlay, $data['xpos'], $data['ypos'], $data['alpha']);
+  }
+  return FALSE;
+}
+
+
+/**
+ * Image effect form callback for the overlay: source image to canvas effect.
+ *
+ * @param array $data
+ *   The current configuration for this image effect.
+ *
+ * @return array
+ *   The form definition for this effect.
+ */
+function canvasactions_source2canvas_form($data) {
+  $defaults = array(
+    'xpos' => '',
+    'ypos' => '',
+    'alpha' => '100',
+    'path' => '',
+  );
+  $data = array_merge($defaults, (array) $data);
+
+  $form = imagecache_actions_pos_form($data);
+  $form['alpha'] = array(
+    '#type' => 'textfield',
+    '#title' => t('opacity'),
+    '#default_value' => $data['alpha'],
+    '#size' => 6,
+    '#description' => t('Opacity: 0-100.'),
+  );
+  return $form;
+}
+
+/**
+ * Implements theme_hook() for the overlay: source img to canvas effect summary.
+ *
+ * @param array $variables
+ *   An associative array containing:
+ *   - data: The current configuration for this image effect.
+ *
+ * @return string
+ *   The HTML for the summary of this image effect.
+ * @ingroup themeable
+ */
+function theme_canvasactions_source2canvas_summary(array $variables) {
+  $data = $variables['data'];
+  return 'xpos:' . $data['xpos'] . ', ypos:' . $data['ypos'] . ' alpha:' . $data['alpha'] . '%';
+}
+
+/**
+ * Image effect callback for the overlay: source image to canvas effect.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *
+ * @return boolean
+ *   true on success, false otherwise.
+ */
+function canvasactions_source2canvas_effect(stdClass $image, array $data) {
+  $overlay = image_load($image->source, $image->toolkit);
+  return image_overlay($image, $overlay, $data['xpos'], $data['ypos'], $data['alpha']);
+}
+
+
+/**
+ * Image effect form callback for the aspect switcher effect.
+ *
+ * @param array $data
+ *   The current configuration for this image effect.
+ *
+ * @return array
+ *   The form definition for this effect.
+ */
+function canvasactions_aspect_form(array $data) {
+  $defaults = array(
+    'ratio_adjustment' => 1,
+    'portrait' => '',
+    'landscape' => '',
+  );
+  $data = array_merge($defaults, (array) $data);
+
+  $form = array(
+    'help' => array(
+      '#markup' => t('You must create the two presets to use <em>before</em> enabling this process.'),
+    )
+  );
+
+  // The PASS_THROUGH parameter is new as of D7.23, and is added here to prevent
+  // image_style_options() from double-encoding the human-readable image style
+  // name, since the form API will already sanitize options in a select list.
+  $styles = image_style_options(TRUE, PASS_THROUGH);
+  // @todo: remove the current style to prevent (immediate) recursion?
+
+  $form['portrait'] = array(
+    '#type' => 'select',
+    '#title' => t('Style to use if the image is portrait (vertical)'),
+    '#default_value' => $data['portrait'],
+    '#options' => $styles,
+    '#description' => t('If you choose none, no extra processing will be done.'),
+  );
+  $form['landscape'] = array(
+    '#type' => 'select',
+    '#title' => t('Style to use if the image is landscape (horizontal)'),
+    '#default_value' => $data['landscape'],
+    '#options' => $styles,
+    '#description' => t('If you choose none, no extra processing will be done.'),
+  );
+
+  $form['ratio_adjustment'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Ratio Adjustment (advanced)'),
+    '#size' => 3,
+    '#default_value' => $data['ratio_adjustment'],
+    '#description' => t("
+This allows you to bend the rules for how different the proportions need to be to trigger the switch.
+<br/>If the (width/height)*n is greater than 1, use 'landscape', otherwise use 'portrait'.
+<br/>When n = 1 (the default) it will switch between portrait and landscape modes.
+<br/>If n > 1, images that are slightly wide will still be treated as portraits.
+If n < 1 then blunt portraits will be treated as landscape.
+    "),
+  );
+  return $form;
+}
+
+
+/**
+ * Implements theme_hook() for the aspect switcher effect summary.
+ *
+ * @param array $variables
+ *   An associative array containing:
+ *   - data: The current configuration for this image effect.
+ *
+ * @return string
+ *   The HTML for the summary of this image effect.
+ * @ingroup themeable
+ */
+function theme_canvasactions_aspect_summary(array $variables) {
+  $data = $variables['data'];
+
+  $label = imagecache_actions_get_style_label($data['portrait']);
+  $output = t('Portrait size: %label', array('%label' => $label));
+  $label = imagecache_actions_get_style_label($data['landscape']);
+  $output .= ', ' . t('Landscape size: %label', array('%label' => $label));
+  if ($data['ratio_adjustment'] != 1) {
+    $output .= ', ' . t("(switch at 1:@ratio_adjustment)", array('@ratio_adjustment' => $data['ratio_adjustment']));
+  }
+  return trim($output);
+}
+
+/**
+ * Image effect callback for the aspect switcher effect.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *
+ * @return boolean
+ *   true on success, false otherwise.
+ */
+function canvasactions_aspect_effect(stdClass $image, array $data) {
+  $ratio_adjustment = isset($data['ratio_adjustment']) ? floatval( $data['ratio_adjustment']) : 1;
+  $aspect = $image->info['width'] / $image->info['height'];
+
+  // width / height * adjustment. If > 1, it's wide.
+  $style_name = (($aspect * $ratio_adjustment) > 1) ? $data['landscape'] : $data['portrait'];
+
+  if (empty($style_name)) {
+    // Do nothing. just return what we've got.
+    return TRUE;
+  }
+
+  $style = image_style_load($style_name);
+
+  if (empty($style)) {
+    // Required preset has gone missing?
+    watchdog('imagecache_actions', "When running 'aspect' action, I was unable to load sub-action %style_name. Either it's been deleted or the DB needs an update", array('%style_name' => $style_name), WATCHDOG_ERROR);
+    return FALSE;
+  }
+
+  // Run the preset actions ourself.
+  foreach ($style['effects'] as $sub_effect) {
+    image_effect_apply($image, $sub_effect);
+  }
+  return TRUE;
+}
+
+/**
+ * Image dimensions callback for the aspect switcher effect.
+ *
+ * @param array $dimensions
+ *   Dimensions to be modified - an associative array containing the items
+ *   'width' and 'height' (in pixels).
+ * @param array $data
+ *   An associative array containing the effect data.
+ */
+function canvasactions_aspect_dimensions(array &$dimensions, array $data) {
+  if (!isset($dimensions['width']) || !isset($dimensions['height'])) {
+    // We cannot know which preset would be executed and thus cannot know the
+    // resulting dimensions, unless both styles return the same dimensions:
+    $landscape_dimensions = $portrait_dimensions = $dimensions;
+    image_style_transform_dimensions($data['landscape'], $landscape_dimensions);
+    image_style_transform_dimensions($data['portrait'], $portrait_dimensions);
+    if ($landscape_dimensions == $portrait_dimensions) {
+      $dimensions = $landscape_dimensions;
+    }
+    else {
+      $dimensions['width'] = $dimensions['height'] = NULL;
+    }
+  }
+  else {
+    $ratio_adjustment = isset($data['ratio_adjustment']) ? floatval( $data['ratio_adjustment']) : 1;
+    $aspect = $dimensions['width'] / $dimensions['height'];
+    $style_name = (($aspect * $ratio_adjustment) > 1) ? $data['landscape'] : $data['portrait'];
+    image_style_transform_dimensions($style_name, $dimensions);
+  }
+}
+
+/**
+ * Image effect form callback for the resize percent effect.
+ *
+ * @param array $data
+ *   The current configuration for this image effect.
+ *
+ * @return array
+ *   The form definition for this effect.
+ */
+function canvasactions_resizepercent_form(array $data) {
+  $defaults = array(
+    'width' => '',
+    'height' => '',
+  );
+  $data = array_merge($defaults, (array) $data);
+
+  $form['#element_validate'] = array('image_effect_scale_validate');
+
+  $form['width'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Width'),
+    '#default_value' => !empty($data['width']) ? (float) $data['width'] : '',
+    '#field_suffix' => ' ' . t('percent'),
+    '#required' => FALSE,
+    '#size' => 10,
+    '#element_validate' => array('canvasactions_resizepercent_validate'),
+    '#allow_negative' => FALSE,
+  );
+  $form['height'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Height'),
+    '#default_value' => !empty($data['height']) ? (float) $data['height'] : '',
+    '#field_suffix' => ' ' . t('percent'),
+    '#required' => FALSE,
+    '#size' => 10,
+    '#element_validate' => array('canvasactions_resizepercent_validate'),
+    '#allow_negative' => FALSE,
+  );
+
+  return $form;
+}
+
+
+/**
+ * Element validate handler to ensure that a positive number is specified.
+ */
+function canvasactions_resizepercent_validate($element, &$form_state) {
+  element_validate_number($element, $form_state);
+  if (!form_get_error($element)) {
+    if ($element['#value'] != ''  && (float) $element['#value'] <= 0) {
+      form_error($element, t('!name must be a positive number.', array('!name' => $element['#title'])));
+    }
+  }
+}
+/**
+ * Calculate percent based on input, fallback if only one value is provided.
+ *
+ * @param array $data
+ *
+ * @return float[]|FALSE
+ */
+function _canvasactions_resizepercent_calculate_percent(array $data) {
+  // Fallback if only one value is provided.
+  if (empty($data['height'])) {
+    if (empty($data['width'])) {
+      return FALSE;
+    }
+    $data['height'] = $data['width'];
+  }
+  else if (empty($data['width'])) {
+    $data['width'] = $data['height'];
+  }
+
+  // Get percentage values in decimal values.
+  $data['width'] = (float) $data['width'] / 100;
+  $data['height'] = (float) $data['height'] / 100;
+
+  return $data;
+}
+
+/**
+ * Implements theme_hook() for the resize percent effect summary.
+ *
+ * @param array $variables
+ *   An associative array containing:
+ *   - data: The current configuration for this image effect.
+ *
+ * @return string
+ *   The HTML for the summary of this image effect.
+ * @ingroup themeable
+ */
+function theme_canvasactions_resizepercent_summary(array $variables) {
+  $data = _canvasactions_resizepercent_calculate_percent($variables['data']);
+  if (!$data) {
+    return t('Invalid effect data');
+  }
+  if ($data['width'] != $data['height']) {
+    return t('@width%x@height%', array('@width' => 100 * $data['width'], '@height' => 100 * $data['height']));
+  }
+  else {
+    return t('scale to @percent%', array('@percent' => (float) 100 * $data['height']));
+  }
+}
+
+/**
+ * Image effect callback for the resize percent effect.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *
+ * @return boolean
+ *   true on success, false otherwise.
+ */
+function canvasactions_resizepercent_effect(stdClass $image, array $data) {
+  $data = _canvasactions_resizepercent_calculate_percent($data);
+
+  $data['width'] = (int) round($image->info['width'] * $data['width']);
+  $data['height'] = (int) round($image->info['height'] * $data['height']);
+
+  return image_resize_effect($image, $data);
+}
+
+/**
+ * Image dimensions callback for the resize percent effect.
+ *
+ * @param array $dimensions
+ *   Dimensions to be modified - an associative array containing the items
+ *   'width' and 'height' (in pixels).
+ * @param array $data
+ *   An associative array containing the effect data.
+ */
+function canvasactions_resizepercent_dimensions(array &$dimensions, array $data) {
+  $data = _canvasactions_resizepercent_calculate_percent($data);
+
+  $dimensions['width'] = (int) round($dimensions['width'] * $data['width']);
+  $dimensions['height'] = (int) round($dimensions['height'] * $data['height']);
+}
+
+/**
+ * Image effect form callback for the blur effect.
+ *
+ * @param array $data
+ *   The current configuration for this image effect.
+ *
+ * @return array
+ *   The form definition for this effect.
+ */
+function canvasactions_blur_form(array $data) {
+  $form['intensity'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Blur intensity'),
+    '#description' => t('A higher intensity results in more blur. The larger the image, the larger value you need to get a really blurred image, think 50 to 100 for 600x400 images.'),
+    '#size' => 5,
+    '#default_value' => isset($data['intensity']) ? (int) $data['intensity'] : 2,
+    '#element_validate' => array('element_validate_integer_positive'),
+  );
+  return $form;
+}
+
+/**
+ * Implements theme_hook() for the underlay (background) effect summary.
+ *
+ * @param array $variables
+ *   An associative array containing:
+ *   - data: The current configuration for this image effect.
+ *
+ * @return string
+ *   The HTML for the summary of this image effect.
+ * @ingroup themeable
+ */
+function theme_canvasactions_blur_summary($variables) {
+  return t('Intensity: @intensity', array('@intensity' => $variables['data']['intensity']));
+}
+
+/**
+ * Image effect callback for the resize percent effect.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *
+ * @return boolean
+ *   true on success, false otherwise.
+ */
+function canvasactions_blur_effect(stdClass $image, array $data) {
+  return image_toolkit_invoke('blur', $image, $data);
+}
+
+/**
+ * GD toolkit specific implementation of the blur effect.
+ *
+ * @param stdClass $image
+ * @param int $intensity
+ *   The number of times to apply the blur filter.
+ *
+ * @return boolean
+ *   True on success, false otherwise.
+ */
+function image_gd_blur(stdClass $image, $intensity) {
+  $intensity = (int) $intensity;
+  $result = TRUE;
+  $i = 0;
+  while ($result && $i++ < $intensity) {
+    $result = imagefilter($image->resource, IMG_FILTER_GAUSSIAN_BLUR);
+  }
+  return $result;
+}
+
+/**
+ * Imagemagick toolkit specific implementation of the blur effect.
+ *
+ * See http://www.imagemagick.org/Usage/blur/.
+ *
+ * @param stdClass $image
+ * @param int $intensity
+ *   The "intensity" of the blur effect.
+ *
+ * @return boolean
+ *   True on success, false otherwise.
+ */
+function image_imagemagick_blur(stdClass $image, $intensity) {
+  // To get similar results asd with the GD factor, we use a formula to alter
+  // the intensity into the sigma value that is passed to IM.
+  $sigma = 4.0 + 0.8 * $intensity;
+  $image->ops[] = '-blur ' . escapeshellarg(sprintf('0x%f', $sigma));
+  return TRUE;
+}
+
+/**
+ * Builds the interlace form.
+ *
+ * This effect has no options, only some help text, so the form is displayed
+ * anyway.
+ */
+function canvasactions_interlace_form() {
+  $form = array();
+  $form['help'] = array(
+    '#markup' => '<p><strong>There are no user-configurable options for this process.</strong></p>
+      <p>This effect will save the derivative image in an interlace / progressive way
+      which might improve perceived performance, especially for large images.
+      File size and loading speed will not change, but the user will pretty quickly
+      see a "degraded" copy of the entire image instead of a clear copy of the upper
+      part of the image.</p>
+      <p>Wikipedia: <a href="https://en.wikipedia.org/wiki/Interlacing_(bitmaps)">Interlacing (bitmaps)</a></p>',
+  );
+  return $form;
+}
+
+/**
+ * Image effect callback for the Interlace / Progressive effect.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function canvasactions_interlace_effect(stdClass $image, array $data) {
+  return image_toolkit_invoke('interlace', $image, array($data));
+}
+
+/**
+ * GD toolkit specific implementation of the image interlace effect.
+ *
+ * @param stdClass $image
+ *   Image object containing the GD image resource to operate on.
+ * param array $data
+ *   The current configuration for this image effect.
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function image_gd_interlace($image/*, array $data*/) {
+  imageinterlace($image->resource, 1);
+  return TRUE;
+}
+
+/**
+ * Imagemagick toolkit specific implementation of the image interlace effect.
+ *
+ * @param stdClass $image
+ *   Image object containing the image resource to operate on.
+ * param array $data
+ *   The current configuration for this image effect.
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function image_imagemagick_interlace($image/*, array $data*/) {
+  $image->ops[] = '-interlace Plane';
+  return TRUE;
+}

+ 14 - 0
sites/all/modules/contrib/files/imagecache_actions/canvasactions/imagecache_canvasactions.info

@@ -0,0 +1,14 @@
+name = Imagecache Canvas Actions
+description = Provides image effects for manipulating image canvases: define canvas, image mask, watermark, underlay background image, rounded corners, composite source to image and resize by percent effect. Also provides an aspect switcher (portrait/landscape).
+package = Media
+core = 7.x
+
+dependencies[] = imagecache_actions
+dependencies[] = image
+
+; Information added by Drupal.org packaging script on 2016-02-19
+version = "7.x-1.7"
+core = "7.x"
+project = "imagecache_actions"
+datestamp = "1455872655"
+

+ 221 - 0
sites/all/modules/contrib/files/imagecache_actions/canvasactions/imagecache_canvasactions.module

@@ -0,0 +1,221 @@
+<?php
+
+/**
+ * @file A collection of canvas (layer) type manipulations for imagecache -
+ * including "Watermark"
+ *
+ * Based on first draft of the code by Dimm (imagecache.module 5--1)
+ * https://drupal.org/node/184816
+ *
+ * Rewritten and ported to Imagecache actions API (imagecache.module 5--2) by
+ * dman http://coders.co.nz/
+ *
+ *
+ * Notes about imagecache action extensions. For each action:
+ *
+ * 1: Implement imagecache_HOOK_form($formdata) to define the config form.
+ *
+ * 1a: Implement theme_imagecache_HOOK_form if needed - optional
+ *
+ * 2: Implement imagecache_HOOK_image($image, $data) to DO the process
+ *
+ * 3: Implement theme_imagecache_HOOK($element) to return a text description of
+ * the setting
+ *
+ * 4: Declare the action in HOOK_imagecache_actions()
+ *
+ *
+ * API ref for hook_image()
+ *
+ * @param $image array defining an image file, including  :
+ *
+ *   $image- >source as the filename,
+ *
+ *   $image->info array
+ *
+ *   $image->resource handle on the image object
+ *
+ * @param $action array of settings as defined in your form.
+ *
+ */
+
+if (! function_exists('imagecache_actions_calculate_relative_position') ) {
+  module_load_include('inc', 'imagecache_actions', 'utility');
+}
+
+// @todo There doesn't seem to be a way to specify a file in hook_image_effect_info
+// so placing this here for the time being.
+module_load_include('inc', 'imagecache_canvasactions', 'canvasactions');
+module_load_include('inc', 'imagecache_canvasactions', 'rounded_corners');
+
+/**
+ * Implements hook_image_effect_info().
+ *
+ * Defines information about the supported effects.
+ */
+function imagecache_canvasactions_image_effect_info() {
+  $effects = array();
+
+  $effects['canvasactions_definecanvas'] = array(
+    'label' => t('Define canvas'),
+    'help' => t('Define the size of the working canvas and background color, this controls the dimensions of the output image.'),
+    'effect callback' => 'canvasactions_definecanvas_effect',
+    'dimensions callback' => 'canvasactions_definecanvas_dimensions',
+    'form callback' => 'canvasactions_definecanvas_form',
+    'summary theme' => 'canvasactions_definecanvas_summary',
+  );
+
+  $effects['canvasactions_imagemask'] = array(
+    'label' => t('Image mask'),
+    'help' => t(' Choose the file image you wish to use as a mask, and apply it to the canvas.'),
+    'dimensions passthrough' => TRUE,
+    'effect callback' => 'canvasactions_imagemask_effect',
+    'form callback' => 'canvasactions_imagemask_form',
+    'summary theme' => 'canvasactions_imagemask_summary',
+  );
+
+  $effects['canvasactions_file2canvas'] = array(
+    'label' => t('Overlay (watermark)'),
+    'help' => t('Choose the file image you wish to use as an overlay, and position it in a layer on top of the canvas.'),
+    'dimensions passthrough' => TRUE,
+    'effect callback' => 'canvasactions_file2canvas_effect',
+    'form callback' => 'canvasactions_file2canvas_form',
+    'summary theme' => 'canvasactions_file2canvas_summary',
+  );
+
+  $effects['canvasactions_canvas2file'] = array(
+    'label' => t('Underlay (background)'),
+    'help' => t('Choose the file image you wish to use as an background, and position the processed image on it.'),
+    'effect callback' => 'canvasactions_canvas2file_effect',
+    'dimensions callback' => 'canvasactions_canvas2file_dimensions',
+    'form callback' => 'canvasactions_canvas2file_form',
+    'summary theme' => 'canvasactions_canvas2file_summary',
+  );
+
+  $effects['canvasactions_source2canvas'] = array(
+    'label' => t('Overlay: source image to canvas'),
+    'help' => t('Places the source image onto the canvas for compositing.'),
+    'dimensions passthrough' => TRUE,
+    'effect callback' => 'canvasactions_source2canvas_effect',
+    'form callback' => 'canvasactions_source2canvas_form',
+    'summary theme' => 'canvasactions_source2canvas_summary',
+  );
+
+  $effects['canvasactions_roundedcorners'] = array(
+    'label' => t('Rounded Corners'),
+    'help' => t('This is true cropping, not overlays, so the result <em>can</em> be transparent.'),
+    'dimensions passthrough' => TRUE,
+    'effect callback' => 'canvasactions_roundedcorners_effect',
+    'form callback' => 'canvasactions_roundedcorners_form',
+    'summary theme' => 'canvasactions_roundedcorners_summary',
+  );
+
+  $effects['canvasactions_aspect'] = array(
+    'label' => t('Aspect switcher'),
+    'help' => t('Use different effects depending on whether the image is landscape of portrait shaped. This re-uses other preset definitions, and just chooses between them based on the rule.'),
+    'effect callback' => 'canvasactions_aspect_effect',
+    'dimensions callback' => 'canvasactions_aspect_dimensions',
+    'form callback' => 'canvasactions_aspect_form',
+    'summary theme' => 'canvasactions_aspect_summary',
+  );
+
+  $effects['canvasactions_resizepercent'] = array(
+    'label' => t('Resize (percent)'),
+    'help' => t('Resize the image based on percent. If only a single dimension is specified, the other dimension will be calculated.'),
+    'effect callback' => 'canvasactions_resizepercent_effect',
+    'dimensions callback' => 'canvasactions_resizepercent_dimensions',
+    'form callback' => 'canvasactions_resizepercent_form',
+    'summary theme' => 'canvasactions_resizepercent_summary',
+  );
+
+  $effects['canvasactions_blur'] = array(
+    'label' => t('Blur'),
+    'help' => t('Make the image become unclear.'),
+    'effect callback' => 'canvasactions_blur_effect',
+    'dimensions passthrough' => TRUE,
+    'form callback' => 'canvasactions_blur_form',
+    'summary theme' => 'canvasactions_blur_summary',
+  );
+
+  $effects['canvasactions_interlace'] = array(
+    'label' => t('Interlace / Progressive'),
+    'help' => t('Create interlaced PNG/GIF or progressive JPG.'),
+    'effect callback' => 'canvasactions_interlace_effect',
+    'dimensions passthrough' => TRUE,
+    'form callback' => 'canvasactions_interlace_form',
+  );
+
+  return $effects;
+}
+
+/**
+ * Implements hook_theme().
+ *
+ * Registers theme functions for the effect summaries.
+ */
+function imagecache_canvasactions_theme() {
+  return array(
+    'canvasactions_definecanvas_summary' => array(
+      'variables' => array('data' => NULL),
+      'file' => 'canvasactions.inc',
+    ),
+    'canvasactions_imagemask_summary' => array(
+      'arguments' => array('element' => NULL),
+      'file' => 'canvasactions.inc',
+    ),
+    'canvasactions_file2canvas_summary' => array(
+      'variables' => array('data' => NULL),
+      'file' => 'canvasactions.inc',
+    ),
+    'canvasactions_source2canvas_summary' => array(
+      'variables' => array('data' => NULL),
+      'file' => 'canvasactions.inc',
+    ),
+    'canvasactions_canvas2file_summary' => array(
+      'variables' => array('data' => NULL),
+      'file' => 'canvasactions.inc',
+    ),
+    'canvasactions_roundedcorners_summary' => array(
+      'variables' => array('data' => NULL),
+      'file' => 'canvasactions.inc',
+    ),
+    'canvasactions_aspect_summary' => array(
+      'variables' => array('data' => NULL),
+      'file' => 'canvasactions.inc',
+    ),
+    'canvasactions_resizepercent_summary' => array(
+      'variables' => array('data' => NULL),
+      'file' => 'canvasactions.inc',
+    ),
+    'canvasactions_blur_summary' => array(
+      'variables' => array('data' => NULL),
+      'file' => 'canvasactions.inc',
+    ),
+  );
+}
+
+/**
+ * Implements hook_image_style_flush().
+ *
+ * This hook checks if the image style that is being flushed is used in an
+ * aspect switcher effect. If so, the style that contains the aspect switcher
+ * effect, should be flushed as well as the flushed style was probably changed.
+ *
+ * @param array $flushed_style
+ *   The image style that is being flushed.
+ */
+function imagecache_canvasactions_image_style_flush(/*array*/ $flushed_style) {
+  $styles = image_styles();
+  foreach ($styles as $style) {
+    if ($style['name'] !== $flushed_style['name']) {
+      foreach ($style['effects'] as $effect) {
+        if ($effect['name'] === 'canvasactions_aspect') {
+          if ( (isset($effect['data']['portrait']) && $effect['data']['portrait'] === $flushed_style['name'])
+            || (isset($effect['data']['landscape']) && $effect['data']['landscape'] === $flushed_style['name'])) {
+            image_style_flush($style);
+          }
+        }
+      }
+    }
+  }
+}

+ 329 - 0
sites/all/modules/contrib/files/imagecache_actions/canvasactions/rounded_corners.inc

@@ -0,0 +1,329 @@
+<?php
+
+/**
+ * @file Routines for rounded corners
+ */
+
+/**
+ * Set radius for corner rounding
+ *
+ * Implementation of imagecache_hook_form()
+ *
+ * @param $action array of settings for this action
+ * @return a form definition
+ */
+function canvasactions_roundedcorners_form($action) {
+  if (image_get_toolkit() != 'gd') {
+    drupal_set_message('Rounded corners are not currently supported on all versions of imagemagick. This effect works best with GD image toolkit only.', 'warning');
+  }
+  drupal_add_js(drupal_get_path('module', 'imagecache_actions') . '/imagecache_actions.jquery.js');
+  $defaults = array(
+    'radius' => '16',
+    #'antialias' => TRUE,
+    'independent_corners_set' => array(
+      'independent_corners' => FALSE,
+      'radii' => array(
+        'tl' => 0,
+        'tr' => 0,
+        'bl' => 0,
+        'br' => 0,
+      ),
+    ),
+  );
+  $action = array_merge($defaults, (array) $action);
+
+  $form['radius'] = array(
+    '#type' => 'textfield',
+    '#title' => t('radius'),
+    '#default_value' => $action['radius'],
+    '#size' => 2,
+  );
+
+  $form['independent_corners_set'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Individual Corner Values'),
+    '#collapsible' => TRUE,
+    '#collapsed' => (! $action['independent_corners_set']['independent_corners']),
+  );
+  $form['independent_corners_set']['independent_corners'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Set Corners Independently'),
+    '#default_value' => $action['independent_corners_set']['independent_corners'],
+  );
+  $corners = array(
+    'tl' => t("Top Left Radius"),
+    'tr' => t("Top Right Radius"),
+    'bl' => t("Bottom Left Radius"),
+    'br' => t("Bottom Right Radius"),
+  );
+  // Loop over the four corners and create field elements for them.
+  $form['independent_corners_set']['radii'] = array(
+    '#type' => 'item',
+    '#id' => 'independent-corners-set',
+    '#states' => array(
+      'visible' => array(
+        ':input[name="data[independent_corners_set][independent_corners]"]' => array('checked' => TRUE),
+      ),
+    ),
+  );
+  foreach ($corners as $attribute => $label) {
+    $form['independent_corners_set']['radii'][$attribute] = array(
+      '#type' => 'textfield',
+      '#title' => $label,
+      '#default_value' => 0 + $action['independent_corners_set']['radii'][$attribute],
+      '#size' => 2,
+    );
+  }
+  /*
+   $form['antialias'] = array(
+   '#type' => 'checkbox',
+   '#title' => t('antialias'),
+   '#return_value' => TRUE,
+   '#default_value' => $action['antialias'],
+   '#description' => t('Attempt antialias smoothing when drawing the corners'),
+   );
+   */
+  $form['notes'] = array(
+    '#markup' => t('
+        Note: the rounded corners effect uses true alpha transparency masking.
+        This means that this effect <b>will fail to be saved</b> on jpegs
+        <em>unless</em> you either <ul>
+        <li>convert the image to PNG (using the coloractions filter for that),</li>
+        <li>define a canvas underneath it (using canvasactions-define-canvas) or</li>
+        <li>underlay a solid color (using coloractions-alpha-flatten) or</li>
+        <li>underlay a background image (canvasactions-underlay)</li>
+        </ul>
+        as a later part of this imagecache pipeline.
+        <br/>
+      '),
+  );
+
+  return $form;
+}
+
+function canvasactions_roundedcorners_effect($image, $action) {
+  $independent_corners = !empty($action['independent_corners_set']['independent_corners']);
+  if (!$independent_corners) {
+    // set the independant corners to all be the same.
+    $corners = array('tl', 'tr', 'bl', 'br');
+    foreach ($corners as $key) {
+      // Use the all-the-same radius setting.
+      $action['independent_corners_set']['radii'][$key] = $action['radius'];
+    }
+  }
+
+  return image_toolkit_invoke('roundedcorners', $image, array($action));
+}
+
+/**
+ * Trim rounded corners off an image, using an anti-aliasing algorithm.
+ *
+ * Implementation of hook_image()
+ *
+ * Note, this is not image toolkit-agnostic yet! It just assumes GD.
+ * We can abstract it out once we have something else to abstract to.
+ * In the meantime just don't.
+ *
+ * 'handcoded' rounded corners logic contributed by donquixote 2009-08-31
+ *
+ * @param $image
+ * @param $action
+ */
+function image_gd_roundedcorners($image, $action) {
+  // Read settings.
+  $width = $image->info['width'];
+  $height = $image->info['height'];
+  $radius = $action['radius'];
+  $independent_corners = !empty($action['independent_corners_set']['independent_corners']);
+  $corners = array('tl', 'tr', 'bl', 'br');
+
+  $im = &$image->resource;
+  // Prepare drawing on the alpha channel.
+  imagesavealpha($im, TRUE);
+  imagealphablending($im, FALSE);
+
+  foreach ($corners as $key) {
+    if ($independent_corners && isset($action['independent_corners_set']['radii'][$key])) {
+      $r = $action['independent_corners_set']['radii'][$key];
+    }
+    else {
+      // Use the all-the-same radius setting.
+      $r = $radius;
+    }
+
+    // key can be 'tl', 'tr', 'bl', 'br'.
+    $is_bottom = ($key{0} == 'b');
+    $is_right = ($key{1} == 'r');
+
+    // dx and dy are in "continuous coordinates",
+    // and mark the distance of the pixel middle to the image border.
+    for ($dx = .5; $dx < $r; ++$dx) {
+      for ($dy = .5; $dy < $r; ++$dy) {
+
+        // ix and iy are in discrete pixel indices,
+        // counting from the top left
+        $ix = floor($is_right ? $width -$dx : $dx);
+        $iy = floor($is_bottom ? $height -$dy : $dy);
+
+        // Color lookup at ($ix, $iy).
+        $color_ix = imagecolorat($im, $ix, $iy);
+        $color = imagecolorsforindex($im, $color_ix);
+
+
+        // Do not process opacity if transparency is 100%. Just jump...
+        // Opacity is always 0 on a transparent source pixel.
+        if ($color['alpha'] != 127) {
+          $opacity = _canvasactions_roundedcorners_pixel_opacity($dx, $dy, $r);
+          if ($opacity >= 1) {
+            // we can finish this row,
+            // all following pixels will be fully opaque.
+            break;
+          }
+
+
+          if (isset($color['alpha'])) {
+            $color['alpha'] = 127 - round($opacity * (127 - $color['alpha']));
+          }
+          else {
+            $color['alpha'] = 127 - round($opacity * 127);
+          }
+          // Value should not be more than 127, and not less than 0.
+          $color['alpha'] = ($color['alpha'] > 127) ? 127 : (($color['alpha'] < 0) ? 0 : $color['alpha']);
+        }
+
+        $color_ix = imagecolorallocatealpha($im, $color['red'], $color['green'], $color['blue'], $color['alpha']);
+        imagesetpixel($im, $ix, $iy, $color_ix);
+      }
+    }
+  }
+  return TRUE;
+}
+
+/**
+ * Calculate the transparency value for a rounded corner pixel
+ *
+ * @param $x
+ *   distance from pixel center to image border (left or right)
+ *   should be an integer + 0.5
+ *
+ * @param $y
+ *   distance from pixel center to image border (top or bottom)
+ *   should be an integer + 0.5
+ *
+ * @param $r
+ *   radius of the rounded corner
+ *   should be an integer
+ *
+ * @return float
+ *   opacity value between 0 (fully transparent) and 1 (fully opaque).
+ *
+ * OPTIMIZE HERE! This is a really tight loop, potentially getting called
+ * thousands of times
+ */
+function _canvasactions_roundedcorners_pixel_opacity($x, $y, $r) {
+  if ($x < 0 || $y < 0) {
+    return 0;
+  }
+  else if ($x > $r || $y > $r) {
+    return 1;
+  }
+  $dist_2 = ($r -$x) * ($r -$x) + ($r -$y) * ($r -$y);
+  $r_2 = $r * $r;
+  if ($dist_2 > ($r + 0.8) * ($r + 0.8)) {
+    return 0;
+  }
+  else if ($dist_2 < ($r -0.8) * ($r -0.8)) {
+    return 1;
+  }
+  else {
+    // this pixel needs special analysis.
+    // thanks to a quite efficient algorithm, we can afford 10x antialiasing :)
+    $opacity = 0.5;
+    if ($x > $y) {
+      // cut the pixel into 10 vertical "stripes"
+      for ($dx = -0.45; $dx < 0.5; $dx += 0.1) {
+        // find out where the rounded corner edge intersects with the stripe
+        // this is plain triangle geometry.
+        $dy = $r - $y - sqrt($r_2 - ($r -$x -$dx) * ($r -$x -$dx));
+        $dy = ($dy > 0.5) ? 0.5 : (($dy < -0.5) ? -0.5 : $dy);
+        // count the opaque part of the stripe.
+        $opacity -= 0.1 * $dy;
+      }
+    }
+    else {
+      // cut the pixel into 10 horizontal "stripes"
+      for ($dy = -0.45; $dy < 0.5; $dy += 0.1) {
+        // this is the math:
+        //   ($r-$x-$dx)^2 + ($r-$y-$dy)^2 = $r^2
+        //   $dx = $r - $x - sqrt($r^2 - ($r-$y-$dy)^2)
+        $dx = $r - $x - sqrt($r_2 - ($r -$y -$dy) * ($r -$y -$dy));
+        $dx = ($dx > 0.5) ? 0.5 : (($dx < -0.5) ? -0.5 : $dx);
+        $opacity -= 0.1 * $dx;
+      }
+    }
+    return ($opacity < 0) ? 0 : (($opacity > 1) ? 1 : $opacity);
+  }
+}
+
+
+
+/**
+ * imageapi_roundedcorners
+ */
+function image_imagemagick_roundedcorners($image, $action) {
+  // Based on the imagemagick documentation.
+  // http://www.imagemagick.org/Usage/thumbnails/#rounded
+  // Create arc cut-outs, then mask them.
+  // Draw black triangles and white circles.
+  // draw circle is center: x,y, and a point on the perimeter
+  $corners = array('tl', 'tr', 'bl', 'br');
+  $radii = $action['independent_corners_set']['radii'];
+  $width = $image->info['width'];
+  $height = $image->info['height'];
+  $tl = $radii['tl'];
+  $tr = $radii['tr'];
+  $bl = $radii['bl'];
+  $br = $radii['br'];
+
+  $drawmask = '';
+  if ($tl) {
+    $drawmask .= " fill black polygon 0,0 0,{$tl} {$tl},0";
+    $drawmask .= " fill white circle {$tl},{$tl} {$tl},0";
+  }
+  if ($tr) {
+    $right = $width -$tr;
+    $drawmask .= " fill black polygon {$right},0 {$width},0 {$width},{$tr}";
+    $drawmask .= " fill white circle {$right},{$tr} {$right},0";
+  }
+  if ($bl) {
+    $bottom = $height -$bl;
+    $drawmask .= " fill black polygon 0,{$bottom} 0,{$height} {$bl},{$height}";
+    $drawmask .= " fill white circle {$bl},{$bottom} 0,{$bottom}";
+  }
+  if ($br) {
+    $bottom = $height -$br;
+    $right = $width -$br;
+    $drawmask .= " fill black polygon {$right},{$height} {$width},{$bottom} {$width},{$height}";
+    $drawmask .= " fill white circle {$right},{$bottom} {$width},{$bottom}";
+  }
+  $draw = ' -draw ' . escapeshellarg($drawmask);
+
+  $compose = ' ' . escapeshellcmd('(') . " +clone  -threshold -1 $draw " . escapeshellcmd(')') . ' +matte -compose CopyOpacity -composite ';
+  $image->ops[] = $compose;
+  return TRUE;
+}
+
+/**
+ * Implementation of theme_hook() for imagecache_ui.module
+ */
+function theme_canvasactions_roundedcorners($variables) {
+  $element = $variables['element'];
+  $data = $element['#value'];
+  if (!empty($data['independent_corners_set']['independent_corners'])) {
+    $dimens = join('px | ', $data['independent_corners_set']['radii']) . 'px';
+  }
+  else {
+    $dimens = "Radius: {$data['radius']}px";
+  }
+  return $dimens;
+}

+ 115 - 0
sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/cheap_dropshadow.imagecache_preset.inc

@@ -0,0 +1,115 @@
+<?php
+/**
+ * @file
+ *   Test imagecache preset.
+ *
+ * Created on Dec 29, 2009
+ *
+ * @author 'dman' Dan Morrison http://coders.co.nz/
+ */
+
+$presets['cheap_dropshadow'] = array (
+  'name' => 'cheap_dropshadow',
+  '#weight' => '3.3',
+  'effects' =>
+  array (
+    -1 => array (
+      'weight' => '-1',
+      'module' => 'imagecache_coloractions',
+      'name' => 'coloractions_convert',
+      'data' => array (
+        'format' => 'image/png',
+        'quality' => '95',
+      ),
+    ),
+    0 =>
+    array (
+      'weight' => '0',
+      'module' => 'imagecache_canvasactions',
+      'name' => 'canvasactions_definecanvas',
+      'data' =>
+      array (
+        'RGB' =>
+        array (
+          'HEX' => '999999',
+        ),
+        'under' => 0,
+        'exact' =>
+        array (
+          'width' => '',
+          'height' => '',
+          'xpos' => 'center',
+          'ypos' => 'center',
+        ),
+        'relative' =>
+        array (
+          'leftdiff' => '0',
+          'rightdiff' => '0',
+          'topdiff' => '0',
+          'bottomdiff' => '0',
+        ),
+      ),
+    ),
+    1 =>
+    array (
+      'weight' => '1',
+      'module' => 'imagecache_canvasactions',
+      'name' => 'canvasactions_definecanvas',
+      'data' =>
+      array (
+        'RGB' =>
+        array (
+          'HEX' => '',
+        ),
+        'under' => 1,
+        'exact' =>
+        array (
+          'width' => '',
+          'height' => '',
+          'xpos' => 'center',
+          'ypos' => 'center',
+        ),
+        'relative' =>
+        array (
+          'leftdiff' => '20',
+          'rightdiff' => '0',
+          'topdiff' => '20',
+          'bottomdiff' => '0',
+        ),
+      ),
+    ),
+    2 =>
+    array (
+      'weight' => '2',
+      'module' => 'imagecache_canvasactions',
+      'name' => 'canvasactions_source2canvas',
+      'data' =>
+      array (
+        'xpos' => 0,
+        'ypos' => 0,
+        'alpha' => '100',
+      ),
+    ),
+    3 =>
+    array (
+      'weight' => '3',
+      'module' => 'image',
+      'name' => 'image_scale',
+      'data' =>
+      array (
+        'width' => '200',
+        'height' => '100%',
+        'upscale' => 0,
+      ),
+    ),
+    4 => array (
+      'weight' => '10',
+      'module' => 'imagecache_coloractions',
+      'name' => 'coloractions_convert',
+      'data' => array (
+        'format' => 'image/png',
+        'quality' => '95',
+      ),
+    ),
+  ),
+);

BIN
sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/cheap_dropshadow.jpg


BIN
sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/cheap_dropshadow.png


+ 61 - 0
sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/keyword_positioning.imagecache_preset.inc

@@ -0,0 +1,61 @@
+<?php
+/**
+ * @file
+ *   Test imagecache preset.
+ * 
+ * Created on Dec 29, 2009
+ *
+ * @author 'dman' Dan Morrison http://coders.co.nz/
+ */
+
+$presets['keyword_positioning'] = array (
+  'name' => 'keyword_positioning',
+  '#weight' => 4.2,
+  'effects' => array (
+    array (
+      'weight' => '-1',
+      'module' => 'imagecache_canvasactions',
+      'name' => 'canvasactions_file2canvas',
+      'data' =>  array (
+        'xpos' => 'right',
+        'ypos' => 'top',
+        'alpha' => '100',
+        'path' => drupal_get_path('module', 'imagecache_testsuite') . "/grid-240x160.png",
+      ),
+    ),
+
+    array (
+      'weight' => '0',
+      'module' => 'imagecache_canvasactions',
+      'name' => 'canvasactions_file2canvas',
+      'data' => array (
+        'xpos' => '25%',
+        'ypos' => 'bottom-10%',
+        'path' => 'misc/druplicon.png',
+      ),
+    ),
+
+    array (
+      'weight' => '0',
+      'module' => 'imagecache_canvasactions',
+      'name' => 'canvasactions_file2canvas',
+      'data' => array (
+        'xpos' => '0%',
+        'ypos' => 'top+10%',
+        'path' => 'misc/druplicon.png',
+      ),
+    ),
+
+    array (
+      'weight' => '0',
+      'module' => 'imagecache_canvasactions',
+      'name' => 'canvasactions_file2canvas',
+      'data' => array (
+        'xpos' => 'right+50',
+        'ypos' => '50%',
+        'path' => 'misc/druplicon.png',
+      ),
+    ),
+
+  ),
+);

BIN
sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/keyword_positioning.jpg


+ 47 - 0
sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/positioned_underlay.imagecache_preset.inc

@@ -0,0 +1,47 @@
+<?php
+/**
+ * @file
+ *   Test imagecache preset.
+ *
+ * Created on Dec 29, 2009
+ *
+ * @author 'dman' Dan Morrison http://coders.co.nz/
+ */
+
+$presets['positioned_underlay'] = array (
+  'name' => 'positioned_underlay',
+  '#weight' => 4.4,
+  'effects' => array (
+    0 => array (
+      'module' => 'image',
+      'name' => 'image_scale',
+      'weight' => '0',
+      'data' => array (
+        'width' => '200',
+        'height' => '',
+        'upscale' => 0,
+      ),
+    ),
+    1 => array (
+      'module' => 'imagecache_canvasactions',
+      'name' => 'canvasactions_canvas2file',
+      'weight' => '1',
+      'data' => array (
+        'xpos' => '50',
+        'ypos' => 'bottom+50',
+        'alpha' => '100',
+        'path' => "$filepath/shiny-bg.png",
+        'dimensions' => 'background',
+      ),
+    ),
+    4 => array (
+      'weight' => '10',
+      'module' => 'imagecache_coloractions',
+      'name' => 'coloractions_convert',
+      'data' => array (
+        'format' => 'image/png',
+        'quality' => '95',
+      ),
+    ),
+  ),
+);

BIN
sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/positioned_underlay.png


+ 35 - 0
sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/rotate_alpha.imagecache_preset.inc

@@ -0,0 +1,35 @@
+<?php
+/**
+ * @file
+ *   Test imagecache preset.
+ *
+ * Created on Dec 29, 2009
+ *
+ * @author 'dman' Dan Morrison http://coders.co.nz/
+ */
+
+$presets['rotate_alpha'] = array (
+  'name' => 'rotate_alpha',
+  '#weight' => 1.4,
+  'effects' => array (
+    1 => array (
+      'weight' => '1',
+      'module' => 'image',
+      'name' => 'image_rotate',
+      'data' => array (
+        'degrees' => '15',
+        'random' => 0,
+        'bgcolor' => '',
+      ),
+    ),
+    3 => array (
+      'weight' => '3',
+      'module' => 'imagecache_coloractions',
+      'name' => 'coloractions_convert',
+      'data' => array (
+        'format' => 'image/png',
+        'quality' => '95',
+      ),
+    ),
+  ),
+);

BIN
sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/rotate_alpha.png


+ 36 - 0
sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/rotate_alpha_gif.imagecache_preset.inc

@@ -0,0 +1,36 @@
+<?php
+/**
+ * @file
+ *   Test imagecache preset.
+ *
+ * Created on Dec 29, 2009
+ *
+ * @author 'dman' Dan Morrison http://coders.co.nz/
+ */
+
+$presets['rotate_alpha_gif'] = array (
+  'name' => 'rotate_alpha_gif',
+  '#weight' => 1.5,
+
+  'effects' => array (
+    1 => array (
+      'weight' => '1',
+      'module' => 'image',
+      'name' => 'image_rotate',
+      'data' => array (
+        'degrees' => '15',
+        'random' => 0,
+        'bgcolor' => '',
+      ),
+    ),
+    3 => array (
+      'weight' => '3',
+      'module' => 'imagecache_coloractions',
+      'name' => 'coloractions_convert',
+      'data' => array (
+        'format' => 'image/gif',
+        'quality' => '75',
+      ),
+    ),
+  ),
+);

+ 37 - 0
sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/rotate_scale.imagecache_preset.inc

@@ -0,0 +1,37 @@
+<?php
+/**
+ * @file
+ *   Test imagecache preset.
+ * 
+ * Created on Dec 29, 2009
+ *
+ * @author 'dman' Dan Morrison http://coders.co.nz/
+ */
+
+$presets['rotate_scale'] = array (
+  'name' => 'rotate_scale',
+  '#weight' => 1.2,
+
+  'effects' => array (
+    1 => array (
+      'weight' => '1',
+      'module' => 'image',
+      'name' => 'image_rotate',
+      'data' => array (        
+        'degrees' => '15',
+        'random' => 0,
+        'bgcolor' => '',
+      ),
+    ),
+    2 => array (
+      'weight' => '2',
+      'module' => 'image',
+      'name' => 'image_scale',
+      'data' => array (
+        'width' => '',
+        'height' => '150',
+        'upscale' => TRUE,
+      ),
+    ),
+  ),
+);

BIN
sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/rotate_scale.jpg


+ 60 - 0
sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/rotate_scale_alpha.imagecache_preset.inc

@@ -0,0 +1,60 @@
+<?php
+/**
+ * @file
+ *   Test imagecache preset.
+ *
+ * Created on Dec 29, 2009
+ *
+ * @author 'dman' Dan Morrison http://coders.co.nz/
+ */
+
+$presets['rotate_scale_alpha'] = array (
+  'name' => 'rotate_scale_alpha',
+  '#weight' => 1.6,
+
+  'effects' => array (
+    1 => array (
+      'weight' => '1',
+      'module' => 'image',
+      'name' => 'image_rotate',
+      'data' => array (
+        'degrees' => '65',
+        'random' => 0,
+        'bgcolor' => '',
+      ),
+    ),
+    /*
+     * imageapi resize is NOT alpha-safe. This test case proves the bug.
+     * A work-around is to change format before resizing.
+    2 => array (
+      'weight' => '2',
+      'module' => 'imagecache_coloractions',
+      'name' => 'coloractions_convert',
+      'data' => array (
+        'format' => 'image/png',
+        'quality' => '95',
+      ),
+    ),
+    */
+    3 => array (
+      'weight' => '3',
+      'module' => 'image',
+      'name' => 'image_scale',
+      'data' => array (
+        'width' => '',
+        'height' => '150',
+        'upscale' => TRUE,
+      ),
+    ),
+    4 => array (
+      'weight' => '4',
+      'module' => 'imagecache_coloractions',
+      'name' => 'coloractions_convert',
+      'data' => array (
+        'format' => 'image/png',
+        'quality' => '95',
+      ),
+    ),
+
+  ),
+);

BIN
sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/rotate_scale_alpha.png


+ 34 - 0
sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/rounded.imagecache_preset.inc

@@ -0,0 +1,34 @@
+<?php
+/**
+ * @file
+ *   Test imagecache preset.
+ *
+ * Created on Dec 29, 2009
+ *
+ * @author 'dman' Dan Morrison http://coders.co.nz/
+ */
+
+$presets['rounded'] = array (
+  'name' => 'rounded',
+  '#weight' => 3.0,
+  'effects' => array (
+    1 => array (
+      'weight' => '0',
+      'module' => 'imagecache_canvasactions',
+      'name' => 'canvasactions_roundedcorners',
+      'data' => array (
+        'radius' => '25',
+        'antialias' => true,
+      ),
+    ),
+    2 => array (
+      'weight' => '3',
+      'module' => 'imagecache_coloractions',
+      'name' => 'coloractions_convert',
+      'data' =>array (
+        'format' => 'image/png',
+        'quality' => '95',
+      ),
+    ),
+  ),
+);

BIN
sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/rounded.png


+ 43 - 0
sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/rounded_bl.imagecache_preset.inc

@@ -0,0 +1,43 @@
+<?php
+/**
+ * @file
+ *   Test imagecache preset.
+ *
+ * Created on Dec 29, 2009
+ *
+ * @author 'dman' Dan Morrison http://coders.co.nz/
+ */
+
+$presets['rounded_bl'] = array (
+  'name' => 'rounded_bl',
+  '#weight' => 3.1,
+  'effects' => array (
+    1 => array (
+      'weight' => '0',
+      'module' => 'imagecache_canvasactions',
+      'name' => 'canvasactions_roundedcorners',
+      'data' => array (
+        'radius' => '50',
+        'independent_corners_set' => array (
+          'independent_corners' => 1,
+          'radii' => array (
+            'tl' => '10',
+            'tr' => '0',
+            'bl' => '50',
+            'br' => '10',
+          ),
+        ),
+        'antialias' => true,
+      ),
+    ),
+    2 => array (
+      'weight' => '3',
+      'module' => 'imagecache_coloractions',
+      'name' => 'coloractions_convert',
+      'data' =>array (
+        'format' => 'image/png',
+        'quality' => '95',
+      ),
+    ),
+  ),
+);

BIN
sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/rounded_bl.png


+ 58 - 0
sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/rounded_flattened.imagecache_preset.inc

@@ -0,0 +1,58 @@
+<?php
+/**
+ * @file
+ *   Test imagecache preset.
+ * 
+ * Created on Dec 29, 2009
+ *
+ * @author 'dman' Dan Morrison http://coders.co.nz/
+ */
+
+$presets['rounded_flattened'] = array (
+  'name' => 'rounded_flattened',
+  '#weight' => 3.3,
+
+  'effects' => array (
+    1 => array (
+      'weight' => '0',
+      'module' => 'imagecache_canvasactions',
+      'name' => 'canvasactions_roundedcorners',
+      'data' => array (
+        'radius' => '50',
+        'independent_corners_set' => array (
+          'independent_corners' => 1,
+          'radii' => array (
+            'tr' => '100',
+            'br' => '0',
+            'tl' => '0',
+            'bl' => '0',
+          ),
+        ),
+        'antialias' => true,
+      ),
+    ),
+    2 => array (
+      'weight' => '0',
+      'module' => 'imagecache_canvasactions',
+      'name' => 'canvasactions_definecanvas',
+      'data' => array (
+        'RGB' => array (
+          'HEX' => '333333',
+        ),
+        'under' => 1,
+        'exact' => array (
+          'width' => '',
+          'height' => '',
+          'xpos' => 'center',
+          'ypos' => 'center',
+        ),
+        'relative' => array (
+          'leftdiff' => '2',
+          'rightdiff' => '2',
+          'topdiff' => '2',
+          'bottomdiff' => '2',
+        ),
+      ),
+    ),
+  ),
+);

BIN
sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/rounded_flattened.jpg


BIN
sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/shiny-bg.png


+ 27 - 0
sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/watermark_100.imagecache_preset.inc

@@ -0,0 +1,27 @@
+<?php
+/**
+ * @file
+ *   Test imagecache preset.
+ * 
+ * Created on Dec 29, 2009
+ *
+ * @author 'dman' Dan Morrison http://coders.co.nz/
+ */
+
+$presets['watermark_100'] = array (
+  'name' => 'watermark_100',
+  '#weight' => 4.0,
+  'effects' => array (
+    0 => array (
+      'weight' => '0',
+      'module' => 'imagecache_canvasactions',
+      'name' => 'canvasactions_file2canvas',
+      'data' => array (
+        'xpos' => '10',
+        'ypos' => '5',
+        'alpha' => '100',
+        'path' => 'misc/druplicon.png',
+      ),
+    ),
+  ),
+);

BIN
sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/watermark_100.jpg


+ 27 - 0
sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/watermark_50.imagecache_preset.inc

@@ -0,0 +1,27 @@
+<?php
+/**
+ * @file
+ *   Test imagecache preset.
+ * 
+ * Created on Dec 29, 2009
+ *
+ * @author 'dman' Dan Morrison http://coders.co.nz/
+ */
+
+$presets['watermark_50'] = array (
+  'name' => 'watermark_50',
+  '#weight' => 4.1,
+  'effects' => array (
+    0 => array (
+      'weight' => '0',
+      'module' => 'imagecache_canvasactions',
+      'name' => 'canvasactions_file2canvas',
+      'data' => array (
+        'xpos' => 'right+20',
+        'ypos' => 'bottom',
+        'alpha' => '50',
+        'path' => 'misc/druplicon.png',
+      ),
+    ),
+  ),
+);

BIN
sites/all/modules/contrib/files/imagecache_actions/canvasactions/tests/watermark_50.jpg


+ 66 - 0
sites/all/modules/contrib/files/imagecache_actions/coloractions/imagecache_coloractions.htaccess_creator.inc

@@ -0,0 +1,66 @@
+<?php
+/**
+ * @file Functions to create .htaccess files in public://styles/{image-style}
+ * directories that force the correct Content-Type header.
+ */
+
+/**
+ * Checks for all image style if a .htaccess should be created to force a
+ * correct Content-Type header.
+ */
+function imagecache_coloractions_create_htaccess_all_styles() {
+  $styles = image_styles();
+  foreach ($styles as $style) {
+    imagecache_coloractions_create_htaccess_for_style($style);
+  }
+}
+
+/**
+ * Checks if an image style has a convert format image effect and if so, creates
+ * an .htaccess in the folder where the derivatives for this style are stored
+ * to force the correct Content-Type header.
+ *
+ * @param array $style
+ *
+ * @return bool|null
+ *   True if .htaccess created successfully, false om error, null if no
+ *  .htaccess needed to be created.
+ */
+function imagecache_coloractions_create_htaccess_for_style(array $style) {
+  // If we have multiple convert effects in the same style (I found one during
+  // testing) the last determines the mime type.
+  $format = NULL;
+  foreach ($style['effects'] as $effect) {
+    if ($effect['name'] === 'coloractions_convert') {
+      if (!empty($effect['data']['format'])) {
+        $format = $effect['data']['format'];
+      }
+    }
+  }
+  return $format ? imagecache_coloractions_create_htaccess($style['name'], $format) : NULL;
+}
+
+/**
+ * Creates an .htaccess file in the folder public://styles/%style_name.
+ *
+ * The folder itself will also be created if necessary.
+ *
+ * @param string $style_name
+ * @param string $mimeType
+ *
+ * @return bool
+ *   True on success, false otherwise.
+ */
+function imagecache_coloractions_create_htaccess($style_name, $mimeType) {
+  $forceType = "ForceType $mimeType\n";
+  $directory = "public://styles/$style_name";
+  if (!file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
+    watchdog('imagecache_actions', 'Failed to create style directory: %directory', array('%directory' => $directory), WATCHDOG_ERROR);
+    return FALSE;
+  }
+  if (!file_put_contents("$directory/.htaccess", $forceType)) {
+    watchdog('imagecache_actions', 'Failed to create .htaccess in style directory: %directory', array('%directory' => $directory), WATCHDOG_ERROR);
+    return FALSE;
+  }
+  return TRUE;
+}

+ 18 - 0
sites/all/modules/contrib/files/imagecache_actions/coloractions/imagecache_coloractions.info

@@ -0,0 +1,18 @@
+name = Imagecache Color Actions
+description = Provides image effects color-shifting, invert colors, brightness, posterize and alpha transparency effects. Also provides a change image format effect.
+package = Media
+core = 7.x
+
+dependencies[] = imagecache_actions
+dependencies[] = image
+
+files[] = imagecache_coloractions.module
+files[] = transparency.inc
+files[] = tests/green.imagecache_preset.inc
+
+; Information added by Drupal.org packaging script on 2016-02-19
+version = "7.x-1.7"
+core = "7.x"
+project = "imagecache_actions"
+datestamp = "1455872655"
+

+ 12 - 0
sites/all/modules/contrib/files/imagecache_actions/coloractions/imagecache_coloractions.install

@@ -0,0 +1,12 @@
+<?php
+
+/**
+ * Create an .htaccess file in image style directories that have a change format
+ * image effect to enforce the correct Content-Type header for the derivative
+ * images.
+ */
+function imagecache_coloractions_update_7101(&$sandbox) {
+  module_load_include('module', 'image');
+  include_once dirname(__FILE__) . '/imagecache_coloractions.htaccess_creator.inc';
+  imagecache_coloractions_create_htaccess_all_styles();
+}

+ 1102 - 0
sites/all/modules/contrib/files/imagecache_actions/coloractions/imagecache_coloractions.module

@@ -0,0 +1,1102 @@
+<?php
+
+/**
+ * @file
+ * Additional actions for imagecache processing.
+ *
+ * Exposes some of the simpler PHP 'imagefilter' actions (colorshift,
+ * brightness, negative)
+ * -  A transparency masker for merging with backgrounds.
+ * -  A pseudo - file conversion feature.
+ *
+ * Compatible with the 2008 revision (imagecache 2)
+ *
+ * @author dan http://coders.co.nz
+ * @author sydneyshan http://enigmadigital.net.au
+ */
+
+if (! function_exists('imagecache_actions_calculate_relative_position') ) {
+  module_load_include('inc', 'imagecache_actions', 'utility');
+}
+module_load_include('inc', 'imagecache_actions', 'utility-color');
+
+// There is no way to specify a file in hook_image_effect_info,
+// so placing this here for the time being.
+include_once dirname(__FILE__) . '/transparency.inc';
+
+/**
+ * Implements hook_image_effect_info().
+ *
+ * Defines information about the supported effects.
+ */
+function imagecache_coloractions_image_effect_info() {
+  // @todo: standardize naming. requires a hook_update_n().
+  $effects = array();
+
+  $effects['coloractions_colorshift'] = array(
+    'label' => t('Color Shift'),
+    'help' => t('Adjust image colors.'),
+    'effect callback' => 'coloractions_colorshift_effect',
+    'dimensions passthrough' => TRUE,
+    'form callback' => 'coloractions_colorshift_form',
+    'summary theme' => 'coloractions_colorshift_summary',
+  );
+
+  $effects['imagecache_coloroverlay'] = array(
+    'label' => t('Color Overlay'),
+    'help' => t('Apply a color tint to an image (retaining blacks and whites).'),
+    'effect callback' => 'coloractions_coloroverlay_effect',
+    'dimensions passthrough' => TRUE,
+    'form callback' => 'coloractions_coloroverlay_form',
+    'summary theme' => 'coloractions_coloroverlay_summary',
+  );
+
+  $effects['coloractions_brightness'] = array(
+    'label' => t('Brightness'),
+    'help' => t('Adjust image brightness.'),
+    'effect callback' => 'coloractions_brightness_effect',
+    'dimensions passthrough' => TRUE,
+    'form callback' => 'coloractions_brightness_form',
+    'summary theme' => 'coloractions_brightness_summary',
+  );
+
+  // @todo: changing inverse to invert at this place requires a hook_update_n().
+  $effects['coloractions_inverse'] = array(
+    'label' => t('Negative Image'),
+    'help' => t('Invert colors and brightness.'),
+    'effect callback' => 'coloractions_invert_effect',
+    'dimensions passthrough' => TRUE,
+    'form callback' => 'coloractions_invert_form',
+    'summary theme' => 'coloractions_invert_summary',
+  );
+
+  // @todo Convert may need a little more work.
+  $effects['coloractions_convert'] = array(
+    'label' => t('Change file format'),
+    'help' => t('Choose to save the image as a different filetype.'),
+    'effect callback' => 'coloractions_convert_effect',
+    'dimensions passthrough' => TRUE,
+    'form callback' => 'coloractions_convert_form',
+    'summary theme' => 'coloractions_convert_summary',
+  );
+
+  $effects['coloractions_posterize'] = array(
+    'label' => t('Posterize'),
+    'help' => t('Reduce the image to a limited number of color levels per channel.'),
+    'effect callback' => 'coloractions_posterize_effect',
+    'dimensions passthrough' => TRUE,
+    'form callback' => 'coloractions_posterize_form',
+    'summary theme' => 'coloractions_posterize_summary',
+  );
+
+  $effects['imagecache_alpha'] = array(
+    'label' => t('Alpha Transparency'),
+    'help' => t('Adjust transparency.'),
+    'effect callback' => 'coloractions_alpha_effect',
+    'dimensions passthrough' => TRUE,
+    'form callback' => 'coloractions_alpha_form',
+    'summary theme' => 'coloractions_alpha_summary',
+  );
+
+  $effects['imagecache_adjustlevels'] = array(
+    'label' => t('Adjust Levels'),
+    'help' => t('Adjust the color levels of the image.'),
+    'effect callback' => 'coloractions_adjustlevels_effect',
+    'dimensions passthrough' => TRUE,
+    'form callback' => 'coloractions_adjustlevels_form',
+    'summary theme' => 'coloractions_adjustlevels_summary',
+
+  );
+
+  $effects['imagecache_desaturatealpha'] = array(
+    'label' => t('Desaturate Alpha'),
+    'help' => t('Desaturate the image while retaining transparency.'),
+    'effect callback' => 'coloractions_desaturatealpha_effect',
+    'dimensions passthrough' => TRUE,
+    'summary theme' => 'coloractions_desaturatealpha_summary',
+  );
+
+  return $effects;
+}
+
+/**
+ * Implements hook_theme().
+ *
+ * Registers theme functions for the effect summaries.
+ */
+function imagecache_coloractions_theme() {
+  return array(
+    'coloractions_colorshift_summary' => array(
+      'variables' => array('data' => NULL),
+    ),
+    'coloractions_coloroverlay_summary' => array(
+      'variables' => array('data' => NULL),
+    ),
+    'coloractions_brightness_summary' => array(
+      'variables' => array('data' => NULL),
+    ),
+    'coloractions_convert_summary' => array(
+      'variables' => array('data' => NULL),
+    ),
+    'coloractions_posterize_summary' => array(
+      'variables' => array('data' => NULL),
+    ),
+    'coloractions_alpha_summary' => array(
+      'variables' => array('data' => NULL),
+      'file' => 'transparency.inc',
+    ),
+    'coloractions_adjustlevels_summary' => array(
+      'variables' => array('data' => NULL),
+    ),
+    'coloractions_desaturatealpha_summary' => array(
+      'variables' => array('data' => NULL),
+    ),
+  );
+}
+
+/**
+ * Implements hook_image_style_flush().
+ *
+ * This hook checks if the style contains a change format image effect and, if
+ * so, creates an .htaccess file in the root of the derivative folder that
+ * forces the correct Content-Type header on images served from that folder.
+ *
+ * @param array $style
+ */
+function imagecache_coloractions_image_style_flush($style) {
+  if (!is_array($style)) {
+    // See [#2190759].
+    return;
+  }
+  // Error in core: the old style + set of effects is passed in. This means
+  // that when a convert effect is added or deleted we won't notice. So we
+  // "change" the order of execution by duplicating these lines from
+  // image_style_flush():
+  // Clear image style and effect caches.
+  cache_clear_all('image_styles', 'cache');
+  cache_clear_all('image_effects:', 'cache', TRUE);
+  drupal_static_reset('image_styles');
+  drupal_static_reset('image_effects');
+
+  // Now load the current state of our style.
+  $new_style = image_style_load(isset($style['name']) ? $style['name'] : NULL, isset($style['isid']) ? $style['isid'] : NULL);
+
+  // If the style is flushed because it is being deleted it might be gone.
+  if (is_array($new_style)) {
+    // Now back to our actual work: determine if we have to crate an .htaccess
+    // file.
+    include_once dirname(__FILE__) . '/imagecache_coloractions.htaccess_creator.inc';
+    imagecache_coloractions_create_htaccess_for_style($new_style);
+  }
+}
+
+/**
+ * Image effect form callback for the color shift effect.
+ *
+ * @param array $data
+ *   The current configuration for this image effect.
+ *
+ * @return array
+ *   The form definition for this effect.
+ */
+function coloractions_colorshift_form(array $data) {
+  $defaults = array(
+    'RGB' => array(
+      'HEX' => '#FF0000',
+    ),
+  );
+  $data = array_merge($defaults, (array) $data);
+  $form = array('#theme' => 'imagecache_rgb_form');
+  $form['RGB'] = imagecache_rgb_form($data['RGB']);
+  $form['note'] = array('#value' => t("<p>
+    Note that colorshift is a mathematical filter that doesn't always
+    have the expected result.
+    To shift an image precisely TO a target color,
+    desaturate (greyscale) it before colorizing.
+    The hue (color wheel) is the <em>direction</em> the
+    existing colors are shifted. The tone (inner box) is the amount.
+    Keep the tone half-way up the left site of the color box
+    for best results.
+  </p>"));
+  return $form;
+}
+
+/**
+ * Implements theme_hook() for the color shift effect summary.
+ *
+ * @param array $variables
+ *   An associative array containing:
+ *   - data: The current configuration for this image effect.
+ *
+ * @return string
+ *   The HTML for the summary of this image effect.
+ * @ingroup themeable
+ */
+function theme_coloractions_colorshift_summary(array $variables) {
+  return theme_imagecacheactions_rgb($variables['data']);
+}
+
+/**
+ * Image effect callback for the color shift effect.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function coloractions_colorshift_effect(stdClass $image, array $data) {
+  // convert color from hex (as it is stored in the UI)
+  if ($data['RGB']['HEX'] && $deduced = imagecache_actions_hex2rgba($data['RGB']['HEX'])) {
+    $data['RGB'] = array_merge($data['RGB'], $deduced);
+  }
+  return image_toolkit_invoke('colorshift', $image, array($data));
+}
+
+/**
+ * GD toolkit specific implementation of the color shift effect.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *   The parameters for this effect.
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function image_gd_colorshift(stdClass $image, array $data) {
+  $RGB = $data['RGB'];
+  if (!function_exists('imagefilter')) {
+    module_load_include('inc', 'imagecache_actions', 'imagefilter');
+  }
+  return imagefilter($image->resource, 4, $RGB['red'], $RGB['green'], $RGB['blue']);
+}
+
+/**
+ * Imagemagick toolkit specific implementation of the color shift effect.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *   The parameters for this effect.
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function image_imagemagick_colorshift(stdClass $image, array $data) {
+  $RGB = $data['RGB'];
+  $image->ops[] = "-fill rgb" . escapeshellcmd('(') . "{$RGB['red']},{$RGB['green']},{$RGB['blue']}" . escapeshellcmd(')') . " -colorize 50" . escapeshellcmd('%');
+  return TRUE;
+}
+
+
+/**
+ * Image effect form callback for the color overlay effect.
+ *
+ * @param array $data
+ *   The current configuration for this image effect.
+ *
+ * @return array
+ *   The form definition for this effect.
+ */
+function coloractions_coloroverlay_form(array $data) {
+  $defaults = array(
+    'RGB' => array(
+      'HEX' => '#E2DB6A',
+    ),
+  );
+  $data = array_merge($defaults, (array) $data);
+  $form = array('#theme' => 'imagecache_rgb_form');
+  $form['RGB'] = imagecache_rgb_form($data['RGB']);
+  $form['note'] = array('#value' => t("<p>
+    Note that color overlay is a mathematical filter that doesn't always
+    have the expected result.
+    To shift an image precisely TO a target color,
+    desaturate (greyscale) it before colorizing.
+    The hue (color wheel) is the <em>direction</em> the
+    existing colors are shifted. The tone (inner box) is the amount.
+    Keep the tone half-way up the left site of the color box
+    for best results.
+    </p>"));
+  return $form;
+}
+
+/**
+ * Implements theme_hook() for the color overlay effect summary.
+ *
+ * @param array $variables
+ *   An associative array containing:
+ *   - data: The current configuration for this image effect.
+ *
+ * @return string
+ *   The HTML for the summary of this image effect.
+ * @ingroup themeable
+ */
+function theme_coloractions_coloroverlay_summary(array $variables) {
+  return theme_imagecacheactions_rgb($variables['data']);
+}
+
+/**
+ * Image effect callback for the color overlay effect.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function coloractions_coloroverlay_effect(stdClass $image, array $data) {
+  // convert color from hex (as it is stored in the UI)
+  if ($data['RGB']['HEX'] && $deduced = imagecache_actions_hex2rgba($data['RGB']['HEX'])) {
+    $data['RGB'] = array_merge($data['RGB'], $deduced);
+  }
+  return image_toolkit_invoke('coloroverlay', $image, array($data));
+}
+
+/**
+ * GD toolkit specific implementation of the color overlay effect.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *   The parameters for this effect.
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function image_gd_coloroverlay(stdClass $image, array $data) {
+  $RGB = $data['RGB'];
+
+  $w = $image->info['width'];
+  $h = $image->info['height'];
+
+  for($y=0;$y<$h;$y++) {
+    for($x=0;$x<$w;$x++) {
+      $rgb = imagecolorat($image->resource, $x, $y);
+      $source = imagecolorsforindex($image->resource, $rgb);
+
+      if($source['red'] <= 128){
+        $final_r = (2 * $source['red'] * $RGB['red'])/256;
+      }else{
+        $final_r = 255 - (((255 - (2 * ($source['red'] - 128))) * (255 - $RGB['red']))/256);
+      }
+      if($source['green'] <= 128){
+        $final_g = (2 * $source['green'] * $RGB['green'])/256;
+      }else{
+        $final_g = 255 - (((255 - (2 * ($source['green'] - 128))) * (255 - $RGB['green']))/256);
+      }
+      if($source['blue'] <= 128){
+        $final_b = (2 * $source['blue'] * $RGB['blue'])/256;
+      }else{
+        $final_b = 255 - (((255 - (2 * ($source['blue'] - 128))) * (255 - $RGB['blue']))/256);
+      }
+      $final_colour = imagecolorallocatealpha($image->resource, $final_r, $final_g, $final_b, $source['alpha']);
+      imagesetpixel($image->resource, $x, $y, $final_colour);
+    }
+  }
+
+  return TRUE;
+}
+
+/**
+ * Imagemagick toolkit specific implementation of the color overlay effect.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *   The parameters for this effect.
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function image_imagemagick_coloroverlay(stdClass $image, array $data) {
+  $RGB = $data['RGB'];
+  $image->ops[] = escapeshellcmd('(') . " +clone +matte -fill rgb" . escapeshellcmd('(') . "{$RGB['red']},{$RGB['green']},{$RGB['blue']}" . escapeshellcmd(')') . " -colorize 100" . escapeshellcmd('%') . " +clone +swap -compose overlay -composite " . escapeshellcmd(')') . " -compose SrcIn -composite";
+  return TRUE;
+}
+
+
+/**
+ * Image effect form callback for the brightness effect.
+ *
+ * @param array $data
+ *   The current configuration for this image effect.
+ *
+ * @return array
+ *   The form definition for this effect.
+ */
+function coloractions_brightness_form(array $data) {
+  $default = array('filter_arg1' => '100');
+  $data = array_merge($default, (array) $data);
+  $form = array();
+  $form['help'] = array('#value' => t("The brightness effect seldom looks good on its own, but can be useful to wash out an image before making it transparent - eg for a watermark."));
+  $form['filter_arg1'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Brightness'),
+    '#description' => t('-255 - +255'),
+    '#default_value' => $data['filter_arg1'],
+    '#size' => 3,
+  );
+  return $form;
+}
+
+/**
+ * Implements theme_hook() for the brightness effect summary.
+ *
+ * @param array $variables
+ *   An associative array containing:
+ *   - data: The current configuration for this image effect.
+ *
+ * @return string
+ *   The HTML for the summary of this image effect.
+ * @ingroup themeable
+ */
+function theme_coloractions_brightness_summary(array $variables) {
+  return t("Adjust") . " : " . $variables['data']['filter_arg1'];
+}
+
+/**
+ * Image effect callback for the brightness effect.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function coloractions_brightness_effect(stdClass $image, array $data) {
+  return image_toolkit_invoke('brightness', $image, array($data));
+}
+
+/**
+ * GD toolkit specific implementation of the brightness effect.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *   The parameters for this effect.
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function image_gd_brightness(stdClass $image, array $data) {
+  if (!function_exists('imagefilter')) {
+    module_load_include('inc', 'imagecache_actions', 'imagefilter');  }
+  return imagefilter($image->resource, 2, $data['filter_arg1']);
+}
+
+/**
+ * Imagemagick toolkit specific implementation of the brightness effect.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *   The parameters for this effect.
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function image_imagemagick_brightness(stdClass $image, array $data) {
+  $image->ops[] = "-modulate " . (int)(100 + ( $data['filter_arg1'] / 128 * 100 ));
+  return TRUE;
+}
+
+
+/**
+ * Image effect form callback for the image invert effect.
+ *
+ * This effect has no parameters.
+ *
+ * param array $data
+ *   The current configuration for this image effect.
+ *
+ * @return array
+ *   The form definition for this effect.
+ */
+function coloractions_invert_form(/*array $data*/) {
+  $form = array();
+  return $form;
+}
+
+/**
+ * Image effect callback for the image invert effect.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function coloractions_invert_effect(stdClass $image, array $data) {
+  return image_toolkit_invoke('invert', $image, array($data));
+}
+
+/**
+ * GD toolkit specific implementation of the image invert effect.
+ *
+ * @param stdClass $image
+ *  param array $data
+ *   The parameters for this effect.
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function image_gd_invert(stdClass $image/*, array $data*/) {
+  if (!function_exists('imagefilter')) {
+    module_load_include('inc', 'imagecache_actions', 'imagefilter');
+  }
+  return imagefilter($image->resource, 0);
+}
+
+/**
+ * Imagemagick toolkit specific implementation of the image invert effect.
+ *
+ * param stdClass $image
+ * param array $data
+ *   The parameters for this effect.
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function image_imagemagick_invert(/*stdClass $image, array $data*/) {
+  // @todo
+  return FALSE;
+}
+
+
+/**
+ * Image effect form callback for the convert image format effect.
+ *
+ * @param array $data
+ *   The current configuration for this image effect.
+ *
+ * @return array
+ *   The form definition for this effect.
+ */
+function coloractions_convert_form(array $data) {
+  $defaults = array(
+    'format' => 'image/png',
+    'quality' => '75',
+  );
+  $data = array_merge($defaults, $data);
+
+  $form = array(
+    'help' => array(
+      '#markup' => t("If you've been using transparencies in the process, the result may get saved as a PNG (as the image was treated as a one in in-between processes). If this is not desired (file sizes may get too big) you should use this process to force a flatten action before saving. "),
+    ),
+    'help2' => array(
+      '#markup' => t("For technical reasons, changing the file format within imagecache does <em>not</em> change the filename suffix. A png may be saved as a *.jpg or vice versa. This may confuse some browsers and image software, but most of them have no trouble. "),
+    ),
+    'format' => array(
+      '#title' => t("File format"),
+      '#type' => 'select',
+      '#default_value' => isset($data['format']) ? $data['format'] : 'image/png',
+      '#options' => coloractions_file_formats(),
+    ),
+    'quality' => array(
+      '#type' => 'textfield',
+      '#title' => t('Quality'),
+      '#description' => t('Override the default image quality. Works for Imagemagick only. Ranges from 0 to 100. For jpg, higher values mean better image quality but bigger files. For png it is a combination of compression and filter'),
+      '#size' => 10,
+      '#maxlength' => 3,
+      '#default_value' => $data['quality'],
+      '#field_suffix' => '%',
+    ),
+  );
+
+  return $form;
+}
+
+/**
+ * Implements theme_hook() for the convert image format effect summary.
+ *
+ * @param array $variables
+ *   An associative array containing:
+ *   - data: The current configuration for this image effect.
+ *
+ * @return string
+ *   The HTML for the summary of this image effect.
+ * @ingroup themeable
+ */
+function theme_coloractions_convert_summary($variables) {
+  $data = $variables['data'];
+  $formats = coloractions_file_formats();
+  if ($formats[$data['format']] == 'jpg') {
+    return t('Convert to: @format, quality: @quality%', array(
+    '@format' => $formats[$data['format']],
+    '@quality' => $data['quality']
+    ));
+  }
+  else {
+    return t("Convert to") .": ". $formats[$data['format']];
+  }
+}
+
+/**
+ * Image effect callback for the convert image format effect.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function coloractions_convert_effect(stdClass $image, array $data) {
+  $formats = coloractions_file_formats();
+  $image->info['mime_type'] = $data['format'];
+  $image->info['extension'] = $formats[$data['format']];
+  image_toolkit_invoke('convert', $image, array($data));
+  return TRUE;
+}
+
+/**
+ * GD toolkit specific implementation of the convert image format effect.
+ *
+ * param stdClass $image
+ * param array $data
+ *   The parameters for this effect.
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function image_gd_convert(/*stdClass $image, array $data*/) {
+  return TRUE;
+}
+
+/**
+ * Imagemagick toolkit specific implementation of the color shift effect.
+ *
+ * Converting the image format with imagemagick is done by prepending the output
+ * format to the target file separated by a colon (:). This is done with
+ * hook_imagemagick_arguments_alter(), see below.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *   The parameters for this effect.
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function image_imagemagick_convert(stdClass $image, array $data) {
+  $image->ops['output_format'] = $image->info['extension'];
+  $image->ops['custom_quality_value'] = (int) $data['quality'];
+  return TRUE;
+}
+
+/**
+ * Implements hook_imagemagick_arguments_alter().
+ *
+ * This hook moves a change in output format from the args (action list) to the
+ * destination format setting within the context.
+ */
+function imagecache_coloractions_imagemagick_arguments_alter(&$args, &$context) {
+  if (isset($args['output_format'])) {
+    $context['destination_format'] = $args['output_format'];
+    unset($args['output_format']);
+  }
+  if (isset($args['custom_quality_value'])) {
+    $args['quality'] = sprintf('-quality %d', $args['custom_quality_value']);
+    unset($args['custom_quality_value']);
+  }
+}
+
+/**
+ * Mini mime-type list
+ *
+ * image_type_to_extension and image_type_to_mime_type?
+ */
+function coloractions_file_formats() {
+  return array('image/jpeg' => 'jpg', 'image/gif' => 'gif', 'image/png' => 'png');
+}
+
+
+/**
+ * Image effect form callback for the posterize effect.
+ *
+ * @param array $data
+ *   The current configuration for this image effect.
+ *
+ * @return array
+ *   The form definition for this effect.
+ */
+function coloractions_posterize_form(array $data) {
+  $form = array();
+
+  $form['colors'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Color levels per channel'),
+    '#default_value' => isset($data['colors']) ? $data['colors'] : '',
+    '#required' => TRUE,
+    '#size' => 10,
+    '#element_validate' => array('image_effect_integer_validate'),
+    '#allow_negative' => FALSE,
+    '#description' => t('Number of unique values per color channel to reduce this image to. The transparency channel is left unchanged. This effect can be used to reduce file size on png images.'),
+  );
+
+  return $form;
+}
+
+/**
+ * Implements theme_hook() for the posterize effect summary.
+ *
+ * @param array $variables
+ *   An associative array containing:
+ *   - data: The current configuration for this image effect.
+ *
+ * @return string
+ *   The HTML for the summary of this image effect.
+ * @ingroup themeable
+ */
+function theme_coloractions_posterize_summary(array $variables) {
+  return t(': Reduce to @colors color levels per channel', array('@colors' => $variables['data']['colors']));
+}
+
+/**
+ * Image effect callback for the posterize effect.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function coloractions_posterize_effect(stdClass $image, array $data) {
+  if (!image_toolkit_invoke('posterize', $image, array($data['colors']))) {
+    watchdog('imagecache_actions', 'Image posterize failed using the %toolkit toolkit on %path (%mimetype, %dimensions)', array(
+      '%toolkit' => $image->toolkit,
+      '%path' => $image->source,
+      '%mimetype' => $image->info['mime_type'],
+      '%dimensions' => $image->info['height'] . 'x' . $image->info['height'],
+    ), WATCHDOG_ERROR);
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/**
+ * GD toolkit specific implementation of the posterize effect.
+ *
+ * Based on:
+ * http://www.qtcentre.org/threads/36385-Posterizes-an-image-with-results-identical-to-Gimp-s-Posterize-command?p=167712#post167712
+ *
+ * @param stdClass $image
+ * @param int $colors
+ *   The parameter for this effect.
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function image_gd_posterize(stdClass $image, $colors) {
+  // Value step for colors per channel.
+  $round_to = 255 / ($colors - 1);
+  $alpha_bit_mask = 255 << 24;
+
+  for ($x = imagesx($image->resource); $x--; ) {
+    for ($y = imagesy($image->resource); $y--; ) {
+      $rgb = imagecolorat($image->resource, $x, $y);
+
+      // Use bitmasks to extract numbers we want, faster equivalent to imagecolorsforindex().
+      $a = $rgb & $alpha_bit_mask; // Alpha
+      $r = $rgb >> 16 & 255; // Red
+      $g = $rgb >> 8  & 255; // Green
+      $b = $rgb       & 255; // Blue
+
+      // (int) (value + 0.5) faster equivalent to round() and already an int.
+      $new_r = (int) (((int) ($r / $round_to + 0.5)) * $round_to  + 0.5);
+      $new_g = (int) (((int) ($g / $round_to + 0.5)) * $round_to  + 0.5);
+      $new_b = (int) (((int) ($b / $round_to + 0.5)) * $round_to  + 0.5);
+
+      // Faster equivalent to imagecolorallocatealpha().
+      $color_combined = $a | ($new_r << 16) | ($new_g << 8) | $new_b;
+      imagesetpixel($image->resource, $x, $y, $color_combined);
+    }
+  }
+
+  return TRUE;
+}
+
+/**
+ * Imagemagick toolkit specific implementation of the color shift effect.
+ *
+ * @param stdClass $image
+ * @param int $colors
+ *   The parameter for this effect.
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function image_imagemagick_posterize(stdClass $image, $colors) {
+  // In newer versions of ImageMagick dithering has no effect on posterize.
+  // Turn dithering off on older versions of ImageMagick for consistency.
+  $image->ops[] = ' +dither -posterize ' . (int) $colors;
+  return TRUE;
+}
+
+/**
+ * Image effect form callback for the brightness effect.
+ *
+ * Settings for color level adjustment actions.
+ *
+ * @param array $data
+ *   The current configuration for this image effect.
+ *
+ * @return array
+ *   The form definition for this effect.
+ */
+function coloractions_adjustlevels_form(array $data) {
+
+  $defaults = array(
+    'independent_colors' => FALSE,
+    'all_colors' => array(
+      'low' => 0,
+      'high' => 1,
+    ),
+    'per_color' => array(
+      'low_red' => 0,
+      'high_red' => 1,
+      'low_green' => 0,
+      'high_green' => 1,
+      'low_blue' => 0,
+      'high_blue' => 1,
+    ),
+  );
+  $data = array_merge($defaults, $data);
+
+  $form = array(
+    '#type' => 'container',
+    'help' => array(
+      '#type' => 'markup',
+      '#markup' => t("<p>Adjusting color levels scales the given channels to a range specified by the 'low' and 'high' values.
+      These 'low' and 'high' values can be any value between 0 and 1.
+      E.g. assume that 'low' is 0.2 and 'high' is 0.9.
+      Pixels that had a value of 0, will get a value of 0.2 * 255 = 51 and pixels that had a value of 255, will get a value of 0.9 * 255 = 229.</p>
+      <p>Note that color level adjustment is a mathematical filter and a such doesn't do automatic balancing.</p>"),
+    ),
+    '#element_validate' => array('coloractions_validate_form'),
+  ) ;
+
+  $form['independent_colors'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Set each color independently'),
+    '#default_value' => $data['independent_colors'],
+  );
+
+  $form['all_colors'] = array(
+    '#type' => 'container',
+    '#tree' => TRUE,
+    '#title' => t('All colors range'),
+    '#required' => !$data['independent_colors'],
+    '#states' => array(
+      'visible' => array(':input[name="data[independent_colors]"]' => array('checked' => FALSE)),
+      'required' => array(':input[name="data[independent_colors]"]' => array('checked' => FALSE)),
+    ),
+  );
+  $form['all_colors'] += coloractions_adjustlevels_form_helper(array(
+    'low' => array('title' => t('Low'), 'default' => $data['all_colors']['low']),
+    'high' => array('title' => t('High'), 'default' => $data['all_colors']['high']),
+  ));
+
+  $form['per_color'] = array(
+    '#type' => 'container',
+    '#tree' => TRUE,
+    '#title' => t('Individual Color Ranges'),
+    '#required' => $data['independent_colors'],
+    '#states' => array(
+      'visible' => array(':input[name="data[independent_colors]"]' => array('checked' => TRUE)),
+      'required' => array(':input[name="data[independent_colors]"]' => array('checked' => TRUE)),
+    ),
+  );
+  $form['per_color'] += coloractions_adjustlevels_form_helper(array(
+    'low_red' => array('title' => t('Red Low'), 'default' => $data['per_color']['low_red']),
+    'high_red' => array('title' => t('Red High'), 'default' => $data['per_color']['high_red']),
+    'low_green' => array('title' => t('Green Low'), 'default' => $data['per_color']['low_green']),
+    'high_green' => array('title' => t('Green High'), 'default' => $data['per_color']['high_green']),
+    'low_blue' => array('title' => t('Blue Low'), 'default' => $data['per_color']['low_blue']),
+    'high_blue' => array('title' => t('Blue High'), 'default' => $data['per_color']['high_blue']),
+  ));
+
+  return $form;
+}
+
+/**
+ * Helper function to create the form for the color level adjustment effect.
+ *
+ * @param array $data
+ *   Array containing the form elements
+ *   names as keys for array elements containing title and default value.
+ *
+ * @return array
+ */
+function coloractions_adjustlevels_form_helper(array $data) {
+  $form = array();
+
+  foreach ($data as $name => $value) {
+    $form[$name] = array(
+      '#type' => 'textfield',
+      '#title' => $value['title'],
+      '#default_value' => $value['default'],
+      '#size' => 5,
+      '#element_validate' => array('coloractions_validate_scale_0_1'),
+    );
+  }
+
+  return $form;
+}
+
+/**
+ * Form element validation handler for elements that should contain a number
+ * between 0 and 1.
+ */
+function coloractions_validate_scale_0_1($element/*, &$form_state*/) {
+  $value = $element['#value'];
+  if ($value != '' && (!is_numeric($value) || (float) $value > 1.0 || (float) $value < 0.0)) {
+    form_error($element, t('%name must be a value between 0 and 1.', array('%name' => $element['#title'])));
+  }
+}
+
+/**
+ * Form element validation handler that compares low and high values.
+ */
+function coloractions_validate_form($element/*, &$form_state*/) {
+  $independent_colors = !empty($element['independent_colors']['#value']);
+  if (!$independent_colors) {
+    // Compare low and high.
+    coloractions_validate_low_and_high($element, 'all_colors', '');
+  }
+  else {
+    // Compare low and high per color
+    coloractions_validate_low_and_high($element, 'per_color', '_red');
+    coloractions_validate_low_and_high($element, 'per_color', '_green');
+    coloractions_validate_low_and_high($element, 'per_color', '_blue');
+  }
+}
+
+function coloractions_validate_low_and_high($element, $fieldset, $suffix) {
+  if ((float) $element[$fieldset]["low$suffix"]['#value'] > (float) $element[$fieldset]["high$suffix"]['#value']) {
+    form_error($element[$fieldset]["high$suffix"], t('%name-high must be higher then %name-low.',
+      array('%name-high' => $element[$fieldset]["high$suffix"]['#title'], '%name-low' => $element[$fieldset]["low$suffix"]['#title'])));
+  }
+
+}
+
+/**
+ * Implements theme_hook() for the adjust color levels effect summary.
+ *
+ * @param array $variables
+ *   An associative array containing:
+ *   - data: The current configuration for this image effect.
+ *
+ * @return string
+ *   The HTML for the summary of this image effect.
+ * @ingroup themeable
+ */
+function theme_coloractions_adjustlevels_summary(array $variables) {
+  $data = $variables['data'];
+  if (empty($data['independent_colors'])) {
+    return t('@range',
+      array('@range' => "[{$data['all_colors']['low']} - {$data['all_colors']['high']}]"));
+  }
+  else {
+    return t('red: @red-range, green: @green-range, blue: @blue-range',
+      array('@red-range' => "[{$data['per_color']['low_red']} - {$data['per_color']['high_red']}]",
+      '@green-range' => "[{$data['per_color']['low_green']} - {$data['per_color']['high_green']}]",
+      '@blue-range' => "[{$data['per_color']['low_blue']} - {$data['per_color']['high_blue']}]"));
+  }
+}
+
+/**
+ * Image effect callback for the adjust levels effect.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function coloractions_adjustlevels_effect(stdClass $image, array $data) {
+  return image_toolkit_invoke('adjustlevels', $image, array($data));
+}
+
+/**
+ * GD toolkit specific implementation of the adjust levels effect.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *   The parameters for this effect.
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function image_gd_adjustlevels(stdClass $image, array $data) {
+
+  $width = $image->info['width'];
+  $height = $image->info['height'];
+
+  if ($data['independent_colors']) {
+    $lower_r = $data['per_color']['low_red'] * 255;
+    $factor_r = ($data['per_color']['high_red'] * 255 - $lower_r) / 255;
+    $lower_g = $data['per_color']['low_green'] * 255;
+    $factor_g = ($data['per_color']['high_green'] * 255 - $lower_g) / 255;
+    $lower_b = $data['per_color']['low_blue'] * 255;
+    $factor_b = ($data['per_color']['high_blue'] * 255 - $lower_b) / 255;
+  }
+  else {
+    $lower_r = $lower_g = $lower_b = $data['all_colors']['low'] * 255;
+    $factor_r = $factor_g = $factor_b = ($data['all_colors']['high'] * 255 - $lower_r) / 255;
+  }
+
+  for ($y = 0; $y < $height; $y++) {
+    for ($x = 0; $x < $width; $x++) {
+      $rgb    = imagecolorat($image->resource, $x, $y);
+      $source = imagecolorsforindex($image->resource, $rgb);
+
+      $final_r = $lower_r + $factor_r * $source['red'];
+      $final_g = $lower_g + $factor_g * $source['green'];
+      $final_b = $lower_b + $factor_b * $source['blue'];
+
+      $final_colour = imagecolorallocatealpha($image->resource, $final_r, $final_g, $final_b, $source['alpha']);
+      imagesetpixel($image->resource, $x, $y, $final_colour);
+    }
+  }
+
+  return TRUE;
+}
+
+/**
+ * Implements theme_hook() for the desaturate alpha effect summary.
+ *
+ * param array $variables
+ *   An associative array containing:
+ *   - data: The current configuration for this image effect.
+ *
+ * @return string
+ *   The HTML for the summary of this image effect.
+ * @ingroup themeable
+ */
+function theme_coloractions_desaturatealpha_summary(/*array $variables*/) {
+  return t(': Desaturates the image while retaining transparency.');
+}
+
+/**
+ * Image effect callback for the desaturate alpha effect.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function coloractions_desaturatealpha_effect(stdClass $image, array $data) {
+  return image_toolkit_invoke('desaturatealpha', $image, array($data));
+}
+
+/**
+ * GD toolkit specific implementation of the adjust levels effect.
+ *
+ * @param stdClass $image
+ *  param array $data
+ *   The parameters for this effect.
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function image_gd_desaturatealpha(stdClass $image/*, array $data*/) {
+  imagealphablending($image->resource, FALSE);
+  $result = imagefilter($image->resource, IMG_FILTER_GRAYSCALE);
+  imagealphablending($image->resource, TRUE);
+  return $result;
+}

+ 248 - 0
sites/all/modules/contrib/files/imagecache_actions/coloractions/transparency.inc

@@ -0,0 +1,248 @@
+<?php
+/**
+ * @file Helper functions for the alpha effect.
+ *
+ * @author dan http://coders.co.nz
+ */
+
+/**
+ * Image effect form callback for the alpha effect.
+ *
+ * @param array $data
+ *   The current configuration for this image effect.
+ *
+ * @return array
+ *   The form definition for this effect.
+ */
+function coloractions_alpha_form(array $data) {
+  $defaults = array(
+    'flatten' => FALSE,
+    'RGB' => array('HEX' => '#000000'),
+    'opacity' => 0.5,
+  );
+  $data = array_merge($defaults, (array) $data);
+
+  $form = array();
+  $form['help'] = array(
+    '#markup' => t("
+      <p>You can <em>either</em> set the alpha values of the image to a fixed
+      amount by defining opacity, <em>or</em> choose a color and let the
+      darkness of the image pixels define an opacity.
+      These are different effects. Don't do both
+      or you will just get a plain block of color of a certain opacity.
+    ")
+  );
+
+  $form['opacity'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Opacity'),
+    '#default_value' => $data['opacity'],
+    '#size' => 3,
+    '#description' => t("
+      A decimal between 0 and 1.
+      You can define the amount of transparency to apply, eg 0.8 (80%) opacity
+      will make the image slightly transparent.
+      Use this with <em>no</em> fill color defined for normal results.
+      If you follow up by flattening the image onto white or grey,
+      this will have the effect of partial desaturation.
+    "),
+  );
+
+  $form['description'] = array(
+    '#value' => t(
+      "<p>Alpha toning is an advanced method of greyscaling or colorizing.
+      It works using transparency, not colour matching.
+      The results of this filter are excellent for using as watermarks,
+      and for 'sepia' type imprints on coloured or textured backgrounds.
+      It converts dark areas of the image to opaque, light to transparent.</p>
+      <p>Note that if you are working with JPEGs, this alpha effect will not last into the final image
+      <em>unless</em> you either <strong>flatten</strong> this image against a background color
+      or image in a later process or <strong>convert</strong> it to a PNG before saving
+      using available imagecache actions.</p>"
+    )
+  );
+
+  $form['RGB'] = imagecache_rgb_form($data['RGB']);
+  $form['RGB']['#type'] = 'fieldset';
+  $form['RGB']['#title'] = t('Fill Color');
+  $form['RGB']['HEX']['#description'] = t("
+    Although this image will end up as an alpha transparency mask,
+    it still has to have some colour to be visible.
+    Black is safe. Dark Sepia #704214 is good too.
+    Set it to nothing to not perform any color shift.
+    ");
+
+  $form['flatten'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Flatten Transparency'),
+    '#default_value' => $data['flatten'],
+    '#return_value' => TRUE,
+    '#description' => t("The opposite of adding alpha transparency, 'flatten' will place the given colour solidly behind the image. Use this if you can't trust IE, or you really do want the image filled in with a solid colour."),
+  );
+
+  return $form;
+}
+
+/**
+ * Implements theme_hook() for the alpha effect summary.
+ *
+ * @param array $variables
+ *   An associative array containing:
+ *   - data: The current configuration for this image effect.
+ *
+ * @return string
+ *   The HTML for the summary of this image effect.
+ *
+ * @ingroup themeable
+ */
+function theme_coloractions_alpha_summary(array $variables) {
+  $data = $variables['data'];
+  return ($data['flatten'] ? t("Flatten") : t("Transparent"))
+    . ($data['opacity'] ? " : " . ($data['opacity'] * 100) . '%' : '')
+    . " : " . theme_imagecacheactions_rgb($data['RGB']);
+}
+
+/**
+ * Image effect callback for the alpha effect.
+ *
+ * Either convert light parts of an image to see-through, or place a solid
+ * colour behind areas that would otherwise be see-though
+ *
+ * To save a partially transparent image, the image resource must be switched to
+ * PNG. REMEMBER TO SWITCH IT BACK if needed.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function coloractions_alpha_effect(stdClass $image, array $data) {
+  // @todo: Extract to GD specific function.
+  if (!$data['flatten']) {
+    // Given an image, convert dark areas to opaque, light to transparent.
+    return png_color2alpha($image, $data['RGB']['HEX'], $data['opacity']);
+  }
+  else {
+    // Do the opposite, flatten the transparency ONTO the given color.
+    $info = $image->info;
+
+    if (!$info) {
+      watchdog('imagecache_actions', "Problem converting image to fill behind. Source image returned no info");
+      return FALSE;
+    }
+
+    $base_image = imagecreatetruecolor($info['width'], $info['height']);
+    imagesavealpha($base_image, TRUE);
+    imagealphablending($base_image, FALSE);
+
+    // Start with a solid color.
+    $background_rgb = imagecache_actions_hex2rgba($data['RGB']['HEX']);
+
+    // Setting the background color here solid is what flattens the image.
+    // But what I really want to do is set it colored rgb AND 100% transparent,
+    // in the hope that a failure to render transparency would instead render
+    // THAT colour.
+    $background_color = @imagecolorallocatealpha($base_image, $background_rgb['red'], $background_rgb['green'], $background_rgb['blue'], 0);
+    // But that still doesn't work. Yet somehow I've seen transparent images
+    // that fallback to white, not silver.
+
+    imagefill($base_image, 0, 0, $background_color);
+
+    // And set the overlay behavior back again.
+    imagealphablending($base_image, TRUE);
+
+    // Place the current image over it.
+    if ($result = imagecopy($base_image, $image->resource, 0, 0, 0, 0, $info['width'], $info['height'])) {
+      imagedestroy($image->resource);
+      $image->resource = $base_image;
+    }
+
+    return $result;
+  }
+}
+
+/**
+ * This achieves a tonal effect by converting the images combined tone and
+ * existing transparency into one shade value. This is then used as the ALPHA
+ * transparency for that pixel, while the whole thing is coloured the same
+ * shade. Images 'grey toned' in this manner should sit smoothly on any
+ * background.
+ *
+ * With no color set, use the existing hue.
+ *
+ * To save a partially transparent image, the image resource must be switched to
+ * PNG. ... or maybe not. Just flatten it yourself, or switch the format
+ * yourself. This hack would produce side effects otherwise.
+ *
+ * This algorithm runs maths per-pixel, and therefore is incredibly much more
+ * inefficient than any native routine. Will kill the server on large images.
+ *
+ * @param stdClass $image
+ * @param string $color
+ * @param float $opacity
+ *   between 0 transparent and 1 solid.
+ *
+ * @return bool
+ *   true on success, false otherwise.
+ */
+function png_color2alpha(stdClass $image, $color, $opacity = NULL) {
+  $info = $image->info;
+  if (!$info) {
+    return FALSE;
+  }
+  $im1 = $image->resource;
+
+  imagesavealpha($im1, TRUE);
+  imagealphablending($im1, FALSE);
+
+  if ($color) {
+    $background = imagecache_actions_hex2rgba($color);
+  }
+  $width = imagesx($im1);
+  $height = imagesy($im1);
+
+  if (($width * $height) > (1200 * 1200)) {
+    watchdog('imagecache_actions', __FUNCTION__ . " on {$image->source}. Image is TOO BIG to run the per-pixel algorithm. Aborting.");
+    return FALSE;
+  }
+  for ($i = 0; $i < $height; $i++) {
+    //this loop traverses each row in the image
+    for ($j = 0; $j < $width; $j++) {
+      //this loop traverses each pixel of each row
+      // Get the color & alpha info of the current pixel.
+      $retrieved_color = imagecolorat($im1, $j, $i); // an index
+      $rgba_array = imagecolorsforindex($im1, $retrieved_color);
+      $alpha = 127;
+
+      // Calculate the total shade value of this pixel.
+
+      // If the rule sets a color, then the darkness of the existing
+      // pixel will define the desired alpha value.
+      if ($color) {
+        $lightness = ($rgba_array['red'] + $rgba_array['green'] + $rgba_array['blue']) / 3;
+        // Need to flip the numbers around before doing maths.
+        //$opacity = 1-($rgba_array['alpha']/127);
+        //$darkness = 1-($lightness/256); // 0 is white, 1 is black
+        //$visibility = $darkness * $opacity;
+        //$alpha = (1-$visibility) * 127;
+        $alpha = (1 - ((1 - ($lightness / 256)) * (1 - ($rgba_array['alpha'] / 127)))) * 127;
+      }
+      // If color is NOT set, then the existing color is passed though, only
+      // made somewhat transparent.
+      if (!$color) {
+        $background = $rgba_array;
+      }
+      if ($opacity) {
+        // It's a user-defined alpha value.
+        $alpha = $alpha * $opacity;
+      }
+
+      // Paint the pixel.
+      /** @noinspection PhpUndefinedVariableInspection */
+      $color_to_paint = imagecolorallocatealpha($image->resource, $background['red'], $background['green'], $background['blue'], $alpha);
+      imagesetpixel($image->resource, $j, $i, $color_to_paint);
+    }
+  }
+  return TRUE;
+}

+ 145 - 0
sites/all/modules/contrib/files/imagecache_actions/customactions/README.txt

@@ -0,0 +1,145 @@
+README
+------
+README for the custom actions effect module.
+
+
+Dependencies
+------------
+Hard dependencies:
+- Imagecache actions.
+- Image (Drupal core).
+
+Soft dependencies/recommended modules:
+- Imagemagick (preferred toolkit).
+- PHP filter (Drupal core).
+
+
+Which toolkit?
+--------------
+Personally, I prefer the imagemagick toolkit:
+- It is better in anti-aliasing, try to rotate an image using both toolkits and
+  you will see what I mean.
+- It does not execute in the PHP memory space, so is not restricted by the
+  memory_limit PHP setting.
+- The GD toolkit will, at least on my Windows configuration, keep font files
+  open after a text operation, so you cannot delete, move or rename it anymore.
+
+
+Installing
+----------
+As usual. After enabling the module you can add custom actions to images.
+
+
+Custom action PHP snippets
+--------------------------
+Given the correct permission, the custom action effect allows you to write your
+own PHP snippet that does the requested processing on the image. How it can do
+so, depends on the toolkit.
+
+For all toolkits, the snippet should return true to indicate success and false
+to indicate failure.
+
+GD
+--
+The GD image resource is available in $image->resource. You can call the GD
+functions on this resource. This effect will query the width and height after
+your processing, so you don't have to change that yourself.
+
+Imagemagick
+-----------
+All real image processing is done at the end, if all effects have added their
+command line arguments to the $image->ops array. So your custom action should
+add the imagemagick commands and its parameters by adding new string entries to
+the end of that array.
+
+If your commands change the width or height of the resulting image, you should
+record so by changing $image->info['width'] and/or $image->info['height'].
+
+General
+-------
+To ease your task, this effect makes some information regarding the image being
+processed available in 2 variables: $image and $image_context. These variables
+are readily available in your snippet.
+
+$image is an object containing the following properties:
+- source: string, the source of the image, e.g. public://photo.jpg
+- info: array, example data:
+   - width (int) 180
+   - height  (int) 180
+   - extension (string) png
+   - mime_type (string) image/png
+   - file_size (int) 4417
+- toolkit: string, imagemagick or GD
+- resource: resource. The GD image resource.
+- ops: array. An array of strings with the ImageMagick commands.
+
+$image_context is an associative array containing:
+- effect_data: array, the data of this image effect, example data for the custom
+  action effect:
+   - php  (string)
+- managed_file: object|null. A managed file object containing these properties:
+   - fid (string) 2
+   - uid (string) 1
+   - filename  (string) photo.jpg
+   - uri (string) public://photo.jpg
+   - filemime  (string) image/jpeg
+   - filesize  (string) 445751
+   - status  (string) 1
+   - timestamp (string) 1327525851
+   - metatags  Array [0]
+   - rdf_mapping Array [0]
+- referring_entities: array|null. A nested array with (fully loaded) entities
+  referring to the current image. The 1st level of entries is keyed by the field
+  name, the 2nd by entity type, and the 3rd by entity id. Example data:
+   - field_photo Array [1]
+      - node  Array [1]
+         - 12  Object of: stdClass
+            - nid (string) 12
+            - vid (string) 12
+            - type  (string) page
+            - author ...
+            - timestamp ...
+            - ...
+- entity: object|null, the 1st entity in referring_entities. This is for easy
+  access to the referring entity if it may be assumed that only 1 entity is
+  referring to the current image.
+- image_field: array|null, the 1st image field in entity that is referring to
+  the current image. This is for easy access to the image field data if it may
+  be assumed that only 1 image field is referring to the current image. Example
+  data:
+   - fid (int) 2
+   - alt (string) ...
+   - title (string) ...
+   - ...
+
+Of course there are many other possible useful globals. Think of:
+- base_url
+- base_path
+- base_root
+- is_https
+- user
+- language
+and of course $_SERVER and $_GET.
+
+Using these information you can access entity data as follows:
+
+Specific case (1 entity, of known entity_type, referring to the image):
+<?php
+$entity_type = 'node';
+$field_name = 'my_field';
+$entity = $image_context['entity'];
+$field = field_get_items($entity_type, $entity, $field_name);
+?>
+
+Or the more general case (not knowing the referring type, or multiple entities
+that may be referring to the image):
+<?php
+$referring_entities = $image_context['referring_entities'];
+foreach ($referring_entities as $field_name => $field_referring_entities) {
+  foreach ($field_referring_entities as $entity_type => $entities) {
+    foreach ($entities as $entity_id => $entity) {
+      $field = field_get_items($entity_type, $entity, $field_name);
+    }
+  }
+}
+?>

+ 14 - 0
sites/all/modules/contrib/files/imagecache_actions/customactions/imagecache_customactions.info

@@ -0,0 +1,14 @@
+name = Imagecache Custom Actions
+description = Provides the custom and subroutine image effects.
+package = Media
+core = 7.x
+
+dependencies[] = imagecache_actions
+dependencies[] = image
+
+; Information added by Drupal.org packaging script on 2016-02-19
+version = "7.x-1.7"
+core = "7.x"
+project = "imagecache_actions"
+datestamp = "1455872655"
+

+ 23 - 0
sites/all/modules/contrib/files/imagecache_actions/customactions/imagecache_customactions.install

@@ -0,0 +1,23 @@
+<?php
+/**
+ * Rename 'text' to 'php' in custom action effect data.
+ */
+function imagecache_customactions_update_7100(/*&$sandbox*/) {
+  $effects = db_select('image_effects')
+    ->fields('image_effects')
+    ->condition('name', 'imagecache_customactions', '=')
+    ->execute()
+    ->fetchAll();
+  foreach ($effects as $effect) {
+    $data = unserialize($effect->data);
+    if (array_key_exists('text', $data)) {
+      $data['php'] = $data['text'];
+      unset($data['text']);
+      $data = serialize($data);
+      db_update('image_effects')
+        ->condition('ieid', $effect->ieid)
+        ->fields(array('data' => $data))
+        ->execute();
+    }
+  }
+}

+ 290 - 0
sites/all/modules/contrib/files/imagecache_actions/customactions/imagecache_customactions.module

@@ -0,0 +1,290 @@
+<?php
+
+/**
+ * @file Allows advanced users to code their own PHP image manipulation routines
+ * as part of image style processing.
+ *
+ * @author Originally contributed by crea https://drupal.org/node/325103#comment-
+ * 1076011
+ *
+ * @author merged into imagecache_actions by dman http://coders.co.nz
+ *
+ * custom action effect:
+ * @todo: add description field that editors can use to define their own summary?
+ * @todo: add form field asking if dimensions stay the same (or if the new dimensions are known).
+ * subroutine effect:
+ * @todo: use isid to allow for image style renaming, but also use name to allow export and import (features)
+ */
+
+
+/**
+ * Implements hook_image_effect_info().
+ *
+ * Defines information about the supported effects.
+ */
+function imagecache_customactions_image_effect_info() {
+  $effects = array();
+
+  $effects['imagecache_customactions'] = array(
+    'label' => t('Custom action'),
+    'help' => t('Runs custom PHP code.'),
+    'effect callback' => 'imagecache_customactions_effect',
+    'dimensions callback' => 'imagecache_customactions_dimensions',
+    'form callback' => 'imagecache_customactions_form',
+    'summary theme' => 'imagecache_customactions_summary',
+  );
+
+  $effects['imagecache_subroutine'] = array(
+    'label' => t('Subroutine'),
+    'help' => t('Runs another defined preset on the image.'),
+    'effect callback' => 'imagecache_subroutine_effect',
+    'dimensions callback' => 'imagecache_subroutine_dimensions',
+    'form callback' => 'imagecache_subroutine_form',
+    'summary theme' => 'imagecache_subroutine_summary',
+  );
+
+  return $effects;
+}
+
+/**
+ * Implements hook_theme().
+ *
+ * Registers theme functions for the effect summaries.
+ */
+function imagecache_customactions_theme() {
+  return array(
+    'imagecache_customactions_summary' => array(
+      'variables' => array('data' => NULL),
+    ),
+    'imagecache_subroutine_summary' => array(
+      'variables' => array('data' => NULL),
+    ),
+  );
+}
+
+/**
+ * Implements hook_image_style_flush().
+ *
+ * This hook checks if the image style that is being flushed is used in a
+ * subroutine effect. If so, the style that contains the subroutine effect
+ * should be flushed as well.
+ *
+ * This may lead to recursive calls to image_style_flush() and thus to this
+ * hook. Without loops in styles that call each other as subroutine, this
+ * recursion will always end.
+ *
+ * @param array $flushed_style
+ *   The image style that is being flushed.
+ */
+function imagecache_customactions_image_style_flush(/*array*/ $flushed_style) {
+  $styles = image_styles();
+  foreach ($styles as $style) {
+    if ($style['name'] !== $flushed_style['name']) {
+      foreach ($style['effects'] as $effect) {
+        if ($effect['name'] === 'imagecache_subroutine') {
+          if (isset($effect['data']['subroutine_presetname']) && $effect['data']['subroutine_presetname'] === $flushed_style['name']) {
+            image_style_flush($style);
+          }
+        }
+      }
+    }
+  }
+}
+
+/**
+ * Image effect form callback for the custom action effect.
+ *
+ * Note that this is not a complete form, it only contains the portion of the
+ * form for configuring the effect options. Therefore it does not not need to
+ * include metadata about the effect, nor a submit button.
+ *
+ * @param array $data
+ *   The current configuration for this image effect.
+ *
+ * @return array
+ *   The form definition for this effect.
+ */
+function imagecache_customactions_form(array $data) {
+  // Add defaults.
+  $data += array('php' => 'return TRUE;');
+
+  // Note: we also need to check for the existence of the module: admin has
+  //   all rights, so user_acccess(...) returns TRUE even if the module is not
+  //   enabled and the permission does not exist.
+  $allow_php = module_exists('php') && user_access('use PHP for settings');
+
+  $form = array(
+    'php' => array(
+      '#type' => 'textarea',
+      '#rows' => 12,
+      '#title' => t('PHP code'),
+      '#default_value' => $data['php'],
+      '#disabled' => !$allow_php,
+      '#description' => t("<p>A piece of PHP code that modifies the image.
+It should return a boolean indicating success or failure.
+You will need the '%use_php' permission, defined by the 'PHP filter' module.
+See the help for an extensive explanation of the possibilities.</p>",
+        array('%use_php' => t('Use PHP for settings'))),
+      '#wysiwyg' => FALSE,
+    ),
+  );
+  return $form;
+}
+
+/**
+ * Implements theme_hook() for the custom action effect summary.
+ *
+ * param array $variables
+ *   An associative array containing:
+ *   - data: The current configuration for this image effect.
+ *
+ * @return string
+ *   The HTML for the summary of this image effect.
+ * @ingroup themeable
+ */
+function theme_imagecache_customactions_summary(/*array $variables*/) {
+  return 'Custom PHP code';
+}
+
+/**
+ * Image effect callback for the custom action effect.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *
+ * @return boolean
+ *   true on success, false otherwise.
+ */
+function imagecache_customactions_effect(stdClass $image, array $data) {
+  // Check that the PHP filter module is enabled.
+  $result = module_exists('php');
+  if ($result) {
+    // Get context about the image.
+    module_load_include('inc', 'imagecache_actions', 'utility');
+    $GLOBALS['image_context'] = imagecache_actions_get_image_context($image, $data);
+    $GLOBALS['image'] = $image;
+
+    $result = php_eval('<' . '?php global $image, $image_context; ' . $data['php'] . ' ?' . '>');
+    // php_eval returns '1' if the snippet returns true.
+    $result = $result === '1';
+
+    unset($GLOBALS['image']);
+    unset($GLOBALS['image_context']);
+  }
+
+  if ($result && $image->toolkit == 'GD') {
+    $image->info['width'] = imagesx($image->resource);
+    $image->info['height'] = imagesy($image->resource);
+  }
+
+  return $result;
+}
+
+/**
+ * Image dimensions callback for the custom action effect.
+ *
+ * @param array $dimensions
+ *   Dimensions to be modified - an associative array containing the items
+ *   'width' and 'height' (in pixels).
+ * param array $data
+ *   An associative array containing the effect data.
+ */
+function imagecache_customactions_dimensions(array &$dimensions/*, array $data*/) {
+  $dimensions['width'] = NULL;
+  $dimensions['height'] = NULL;
+}
+
+/**
+ * Subroutine - an imagecache action that just calls another one.
+ *
+ * Contributed by Alan D
+ * https://drupal.org/node/618784
+ *
+ * Reworked into customactions by dman 2010-07
+ */
+
+/**
+ * Image effect form callback for the subroutine effect.
+ *
+ * @param array $data
+ *   The current configuration for this image effect.
+ *
+ * @return array
+ *   The form definition for this effect.
+ */
+function imagecache_subroutine_form(array $data) {
+  // Add defaults.
+  $data += array('subroutine_presetname' => '');
+
+  // List available image styles.
+  // The PASS_THROUGH parameter is new as of D7.23, and is added here to prevent
+  // image_style_options() from double-encoding the human-readable image style
+  // name, since the form API will already sanitize options in a select list.
+  $styles = image_style_options(TRUE, PASS_THROUGH);
+  //@todo: unset the current style to prevent obvious recursion.
+
+  $form = array();
+
+  $form['subroutine_presetname'] = array(
+    '#type' => 'select',
+    '#title' => t('Image style to call'),
+    '#default_value' => $data['subroutine_presetname'],
+    '#options' => $styles,
+    '#required' => TRUE,
+  );
+
+  return $form;
+}
+
+/**
+ * Implements theme_hook() for the subroutine effect summary.
+ *
+ * @param array $variables
+ *   An associative array containing:
+ *   - data: The current configuration for this image effect.
+ *
+ * @return string
+ *   The HTML for the summary of this image effect.
+ * @ingroup themeable
+ */
+function theme_imagecache_subroutine_summary(array $variables) {
+  $data = $variables['data'];
+
+  module_load_include('inc', 'imagecache_actions', 'utility');
+  $label = imagecache_actions_get_style_label($data['subroutine_presetname']);
+  return t('Apply image style %label', array('%label' => $label));
+}
+
+/**
+ * Image effect callback for the subroutine effect.
+ *
+ * @param stdClass $image
+ * @param array $data
+ *
+ * @return boolean
+ *   true on success, false otherwise.
+ */
+function imagecache_subroutine_effect(stdClass $image, array $data) {
+  $result = FALSE;
+  if ($style = image_style_load($data['subroutine_presetname'])) {
+    $result = TRUE;
+    foreach ($style['effects'] as $effect) {
+      $result = $result && image_effect_apply($image, $effect);
+    }
+  }
+  return $result;
+}
+
+/**
+ * Image dimensions callback for the subroutine effect.
+ *
+ * @param array $dimensions
+ *   Dimensions to be modified - an array with components width and height, in
+ *   pixels.
+ * @param array $data
+ *   An array with the effect options.
+ */
+function imagecache_subroutine_dimensions(array &$dimensions, array $data) {
+  // Let the subroutine transform the dimensions.
+  image_style_transform_dimensions($data['subroutine_presetname'], $dimensions);
+}

BIN
sites/all/modules/contrib/files/imagecache_actions/docs/aspect-chaining.png


BIN
sites/all/modules/contrib/files/imagecache_actions/docs/brightness.png


BIN
sites/all/modules/contrib/files/imagecache_actions/docs/canvases.png


BIN
sites/all/modules/contrib/files/imagecache_actions/docs/cheap_dropshadow.png


BIN
sites/all/modules/contrib/files/imagecache_actions/docs/colorshift.png


Some files were not shown because too many files changed in this diff