| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | *  | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | **********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // XXX this is a hack...
 | 
					
						
							|  |  |  | // 		...need a way to escape these so as not to load them in browser...
 | 
					
						
							|  |  |  | if(typeof(process) != 'undefined'){ | 
					
						
							|  |  |  | 	var fs = require('fs') | 
					
						
							|  |  |  | 	var path = require('path') | 
					
						
							|  |  |  | 	var exiftool = require('exiftool') | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | define(function(require){ var module = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //var DEBUG = DEBUG != null ? DEBUG : true
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-24 00:05:58 +03:00
										 |  |  | var util = require('lib/util') | 
					
						
							|  |  |  | var toggler = require('lib/toggler') | 
					
						
							| 
									
										
										
										
											2016-01-18 05:20:14 +03:00
										 |  |  | var tasks = require('lib/tasks') | 
					
						
							| 
									
										
										
										
											2016-03-26 04:01:13 +03:00
										 |  |  | var keyboard = require('lib/keyboard') | 
					
						
							| 
									
										
										
										
											2016-01-18 05:20:14 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | var actions = require('lib/actions') | 
					
						
							|  |  |  | var core = require('features/core') | 
					
						
							| 
									
										
										
										
											2016-01-24 00:05:58 +03:00
										 |  |  | var base = require('features/base') | 
					
						
							| 
									
										
										
										
											2016-05-04 21:28:46 +03:00
										 |  |  | var widgets = require('features/ui-widgets') | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-15 03:40:52 +03:00
										 |  |  | var browse = require('lib/widget/browse') | 
					
						
							|  |  |  | var overlay = require('lib/widget/overlay') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*********************************************************************/ | 
					
						
							| 
									
										
										
										
											2016-01-12 04:47:40 +03:00
										 |  |  | // XXX make metadata a prop of image... (???)
 | 
					
						
							|  |  |  | // XXX Q: should we standardise metadata field names and adapt them to 
 | 
					
						
							|  |  |  | // 		lib???
 | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-12 04:33:10 +03:00
										 |  |  | var MetadataActions = actions.Actions({ | 
					
						
							|  |  |  | 	getMetadata: ['- Image/Get metadata data', | 
					
						
							| 
									
										
										
										
											2016-01-11 04:29:08 +03:00
										 |  |  | 		function(image){ | 
					
						
							|  |  |  | 			var gid = this.data.getImage(image) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if(this.images && this.images[gid]){ | 
					
						
							|  |  |  | 				return this.images[gid].metadata || {} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return null | 
					
						
							|  |  |  | 		}], | 
					
						
							| 
									
										
										
										
											2016-01-12 04:33:10 +03:00
										 |  |  | 	setMetadata: ['- Image/Set metadata data', | 
					
						
							| 
									
										
										
										
											2016-01-11 04:29:08 +03:00
										 |  |  | 		function(image, metadata, merge){ | 
					
						
							|  |  |  | 			var that = this | 
					
						
							|  |  |  | 			var gid = this.data.getImage(image) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if(this.images && this.images[gid]){ | 
					
						
							|  |  |  | 				if(merge){ | 
					
						
							|  |  |  | 					var m = this.images[gid].metadata | 
					
						
							|  |  |  | 					Object.keys(metadata).forEach(function(k){ | 
					
						
							|  |  |  | 						m[k] = metadata[k] | 
					
						
							|  |  |  | 					}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					this.images[gid].metadata = metadata | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}] | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-12 04:33:10 +03:00
										 |  |  | var Metadata =  | 
					
						
							|  |  |  | module.Metadata = core.ImageGridFeatures.Feature({ | 
					
						
							| 
									
										
										
										
											2016-01-11 04:29:08 +03:00
										 |  |  | 	title: '', | 
					
						
							|  |  |  | 	doc: '', | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-12 04:33:10 +03:00
										 |  |  | 	tag: 'metadata', | 
					
						
							| 
									
										
										
										
											2016-01-11 04:29:08 +03:00
										 |  |  | 	depends: [ | 
					
						
							|  |  |  | 		'base', | 
					
						
							|  |  |  | 	], | 
					
						
							| 
									
										
										
										
											2016-04-02 19:30:48 +03:00
										 |  |  | 	suggested: [ | 
					
						
							|  |  |  | 		'fs-metadata', | 
					
						
							|  |  |  | 		'ui-metadata', | 
					
						
							| 
									
										
										
										
											2016-04-13 03:05:25 +03:00
										 |  |  | 		'ui-fs-metadata', | 
					
						
							| 
									
										
										
										
											2016-04-02 19:30:48 +03:00
										 |  |  | 	], | 
					
						
							| 
									
										
										
										
											2016-01-11 04:29:08 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-12 04:33:10 +03:00
										 |  |  | 	actions: MetadataActions, | 
					
						
							| 
									
										
										
										
											2016-01-11 04:29:08 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //---------------------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											2016-01-12 04:33:10 +03:00
										 |  |  | // Metadata reader/writer...
 | 
					
						
							| 
									
										
										
										
											2016-01-11 04:29:08 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-12 04:33:10 +03:00
										 |  |  | // XXX add Metadata writer...
 | 
					
						
							|  |  |  | var MetadataReaderActions = actions.Actions({ | 
					
						
							| 
									
										
										
										
											2016-04-23 00:07:04 +03:00
										 |  |  | 	// NOTE: this will read both stat and metadata...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2016-01-19 01:23:47 +03:00
										 |  |  | 	// XXX add support to taskqueue...
 | 
					
						
							| 
									
										
										
										
											2016-01-11 04:29:08 +03:00
										 |  |  | 	// XXX should this process multiple images???
 | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | 	// XXX also check the metadata/ folder (???)
 | 
					
						
							|  |  |  | 	// XXX this uses .markChanged(..) form filesystem.FileSystemWriter 
 | 
					
						
							|  |  |  | 	// 		feature, but technically does not depend on it...
 | 
					
						
							|  |  |  | 	// XXX should we store metadata in an image (current) or in fs???
 | 
					
						
							| 
									
										
										
										
											2016-01-12 04:33:10 +03:00
										 |  |  | 	readMetadata: ['- Image/Get metadata data', | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | 		function(image, force){ | 
					
						
							|  |  |  | 			var that = this | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var gid = this.data.getImage(image) | 
					
						
							| 
									
										
										
										
											2016-01-15 05:19:42 +03:00
										 |  |  | 			var img = this.images && this.images[gid] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-13 03:05:25 +03:00
										 |  |  | 			if(!image && !img){ | 
					
						
							|  |  |  | 				return false | 
					
						
							| 
									
										
										
										
											2016-01-15 05:19:42 +03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | 			var full_path = path.normalize(img.base_path +'/'+ img.path) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-13 03:05:25 +03:00
										 |  |  | 			return new Promise(function(resolve, reject){ | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | 				if(!force && img.metadata){ | 
					
						
							|  |  |  | 					return resolve(img.metadata) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				fs.readFile(full_path, function(err, file){ | 
					
						
							|  |  |  | 					if(err){ | 
					
						
							|  |  |  | 						return reject(err) | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-23 00:07:04 +03:00
										 |  |  | 					// read stat...
 | 
					
						
							|  |  |  | 					if(!that.images[gid].birthtime){ | 
					
						
							|  |  |  | 						var img = that.images[gid] | 
					
						
							|  |  |  | 						var stat = fs.statSync(full_path) | 
					
						
							|  |  |  | 						 | 
					
						
							|  |  |  | 						img.atime = stat.atime | 
					
						
							|  |  |  | 						img.mtime = stat.mtime | 
					
						
							|  |  |  | 						img.ctime = stat.ctime | 
					
						
							|  |  |  | 						img.birthtime = stat.birthtime | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						img.size = stat.size | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// read image metadata...
 | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | 					exiftool.metadata(file, function(err, data){ | 
					
						
							|  |  |  | 						if(err){ | 
					
						
							|  |  |  | 							reject(err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						} else if(data.error){ | 
					
						
							|  |  |  | 							reject(data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						} else { | 
					
						
							|  |  |  | 							// store metadata...
 | 
					
						
							|  |  |  | 							// XXX 
 | 
					
						
							| 
									
										
										
										
											2016-01-18 05:20:14 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 							// convert to a real dict...
 | 
					
						
							|  |  |  | 							// NOTE: exiftool appears to return an array 
 | 
					
						
							|  |  |  | 							// 		object rather than an actual dict/object
 | 
					
						
							|  |  |  | 							// 		and that is not JSON compatible....
 | 
					
						
							|  |  |  | 							var m = {} | 
					
						
							|  |  |  | 							Object.keys(data).forEach(function(k){ m[k] = data[k] }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							that.images[gid].metadata = m | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-13 03:05:25 +03:00
										 |  |  | 							// XXX
 | 
					
						
							|  |  |  | 							that.markChanged && that.markChanged(gid) | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2016-01-15 05:19:42 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 						resolve(data) | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | 					}) | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		}], | 
					
						
							| 
									
										
										
										
											2016-01-08 07:45:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-18 05:20:14 +03:00
										 |  |  | 	// XXX STUB: add support for this to .readMetadata(..)
 | 
					
						
							| 
									
										
										
										
											2016-04-13 01:17:53 +03:00
										 |  |  | 	readAllMetadata: ['- Image/Read all metadata', | 
					
						
							| 
									
										
										
										
											2016-01-18 05:20:14 +03:00
										 |  |  | 		function(){ | 
					
						
							|  |  |  | 			var that = this | 
					
						
							|  |  |  | 			// XXX make this a global API...
 | 
					
						
							|  |  |  | 			var q = this.__reader_queue = this.__reader_queue || tasks.Queue() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var read = function(gid){  | 
					
						
							|  |  |  | 				return function(){ return that.readMetadata(gid) } } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			q.start() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this.images  | 
					
						
							|  |  |  | 				&& this.images.forEach(function(gid){ | 
					
						
							|  |  |  | 					q.enqueue('metadata', read(gid)) | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 			return q | 
					
						
							|  |  |  | 		}], | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-12 04:33:10 +03:00
										 |  |  | 	// XXX take image Metadata and write it to target...
 | 
					
						
							|  |  |  | 	writeMetadata: ['- Image/Set metadata data', | 
					
						
							| 
									
										
										
										
											2016-01-08 07:45:47 +03:00
										 |  |  | 		function(image, target){ | 
					
						
							| 
									
										
										
										
											2016-01-09 04:59:57 +03:00
										 |  |  | 			// XXX
 | 
					
						
							| 
									
										
										
										
											2016-01-08 07:45:47 +03:00
										 |  |  | 		}] | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-12 04:33:10 +03:00
										 |  |  | var MetadataReader =  | 
					
						
							| 
									
										
										
										
											2016-01-12 04:47:40 +03:00
										 |  |  | module.MetadataReader = core.ImageGridFeatures.Feature({ | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | 	title: '', | 
					
						
							|  |  |  | 	doc: '', | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-12 04:47:40 +03:00
										 |  |  | 	tag: 'fs-metadata', | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | 	depends: [ | 
					
						
							| 
									
										
										
										
											2016-01-12 04:47:40 +03:00
										 |  |  | 		'metadata', | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | 	], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	isApplicable: function(){  | 
					
						
							|  |  |  | 		return this.runtime == 'nw' || this.runtime == 'node' }, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-12 04:33:10 +03:00
										 |  |  | 	actions: MetadataReaderActions, | 
					
						
							| 
									
										
										
										
											2016-01-15 05:19:42 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	handlers: [ | 
					
						
							|  |  |  | 		// XXX STUB: need a better strategy to read metadata...
 | 
					
						
							| 
									
										
										
										
											2016-04-13 01:17:53 +03:00
										 |  |  | 		// 		Approach 1 (target):
 | 
					
						
							|  |  |  | 		// 			read the metadata on demand e.g. on .showMetadata(..)
 | 
					
						
							|  |  |  | 		// 				+ natural approach
 | 
					
						
							|  |  |  | 		// 				- not sync
 | 
					
						
							|  |  |  | 		// 					really complicated to organize...
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// 		Approach 2:
 | 
					
						
							|  |  |  | 		// 			lazy read -- timeout and overwrite on next image
 | 
					
						
							|  |  |  | 		// 				- hack-ish
 | 
					
						
							|  |  |  | 		// 				+ simple
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// 		Approach 3:
 | 
					
						
							|  |  |  | 		// 			index a dir
 | 
					
						
							| 
									
										
										
										
											2016-04-13 03:05:25 +03:00
										 |  |  | 		/* | 
					
						
							| 
									
										
										
										
											2016-01-15 05:19:42 +03:00
										 |  |  | 		['focusImage',  | 
					
						
							|  |  |  | 			function(){ | 
					
						
							|  |  |  | 				var gid = this.current | 
					
						
							|  |  |  | 				metadata = this.images && this.images[gid] && this.images[gid].metadata | 
					
						
							|  |  |  | 				metadata = metadata && (Object.keys(metadata).length > 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if(!metadata){ | 
					
						
							|  |  |  | 					this.readMetadata(gid) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}] | 
					
						
							| 
									
										
										
										
											2016-04-13 03:05:25 +03:00
										 |  |  | 		*/ | 
					
						
							| 
									
										
										
										
											2016-01-15 05:19:42 +03:00
										 |  |  | 	], | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-11 04:29:08 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-08 07:45:47 +03:00
										 |  |  | //---------------------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											2016-01-12 04:33:10 +03:00
										 |  |  | // Metadata editor/viewer...
 | 
					
						
							| 
									
										
										
										
											2016-01-09 01:55:19 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2016-01-16 08:53:03 +03:00
										 |  |  | // NOTE: this is by-design platform independent...
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2016-01-09 01:55:19 +03:00
										 |  |  | // XXX first instinct is to use browse with editable fields as it will
 | 
					
						
							|  |  |  | // 		give us: 
 | 
					
						
							|  |  |  | // 			- searchability
 | 
					
						
							|  |  |  | // 			- navigation
 | 
					
						
							|  |  |  | // 			- ...
 | 
					
						
							|  |  |  | // 		missing functionality:
 | 
					
						
							|  |  |  | // 			- editor/form on open event
 | 
					
						
							|  |  |  | // 				- inline (preferred)
 | 
					
						
							|  |  |  | // 				- modal-form
 | 
					
						
							|  |  |  | // 			- table-like layout
 | 
					
						
							|  |  |  | // 				- template???
 | 
					
						
							|  |  |  | // 				- script layout tweaking (post-update)
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		...need to think about this...
 | 
					
						
							| 
									
										
										
										
											2016-01-08 07:45:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-16 08:53:03 +03:00
										 |  |  | // XXX add ability to manually sort fields -- moving a field up/down 
 | 
					
						
							|  |  |  | // 		edits .config...
 | 
					
						
							| 
									
										
										
										
											2016-01-15 05:19:42 +03:00
										 |  |  | // 		...not sure how to go about this yet...
 | 
					
						
							|  |  |  | // XXX add combined fields...
 | 
					
						
							|  |  |  | // 		'Make' + 'Camera Model Name'
 | 
					
						
							|  |  |  | // XXX add identical fields -- show first available and hide the rest...
 | 
					
						
							|  |  |  | // 		'Shutter Speed', 'Exposure Time',
 | 
					
						
							|  |  |  | // 		'Lens ID', 'Lens'
 | 
					
						
							| 
									
										
										
										
											2016-01-16 08:53:03 +03:00
										 |  |  | // XXX add field editing... (open)
 | 
					
						
							| 
									
										
										
										
											2016-01-19 01:23:47 +03:00
										 |  |  | // XXX might be good to split this to sections...
 | 
					
						
							|  |  |  | // 		- base info
 | 
					
						
							|  |  |  | // 		- general metadata
 | 
					
						
							|  |  |  | // 		- full metadata
 | 
					
						
							|  |  |  | // 			- EXIF
 | 
					
						
							|  |  |  | // 			- IPTC
 | 
					
						
							|  |  |  | // 			- ...
 | 
					
						
							| 
									
										
										
										
											2016-01-12 04:33:10 +03:00
										 |  |  | var MetadataUIActions = actions.Actions({ | 
					
						
							| 
									
										
										
										
											2016-01-12 04:47:40 +03:00
										 |  |  | 	config: { | 
					
						
							| 
									
										
										
										
											2016-01-24 00:05:58 +03:00
										 |  |  | 		'metadata-auto-select-modes': [ | 
					
						
							|  |  |  | 			'none', | 
					
						
							|  |  |  | 			'on select', | 
					
						
							|  |  |  | 			'on open', | 
					
						
							|  |  |  | 		], | 
					
						
							|  |  |  | 		'metadata-auto-select-mode': 'on select', | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-14 16:01:17 +03:00
										 |  |  | 		// XXX
 | 
					
						
							| 
									
										
										
										
											2016-01-24 00:05:58 +03:00
										 |  |  | 		'metadata-editable-fields': [ | 
					
						
							| 
									
										
										
										
											2016-04-14 16:01:17 +03:00
										 |  |  | 			//'Artist',
 | 
					
						
							|  |  |  | 			//'Copyright',
 | 
					
						
							|  |  |  | 			//'Comment',
 | 
					
						
							|  |  |  | 			//'Tags',
 | 
					
						
							| 
									
										
										
										
											2016-01-24 00:05:58 +03:00
										 |  |  | 		], | 
					
						
							| 
									
										
										
										
											2016-01-12 04:47:40 +03:00
										 |  |  | 		'metadata-field-order': [ | 
					
						
							| 
									
										
										
										
											2016-01-24 01:58:48 +03:00
										 |  |  | 			// base
 | 
					
						
							|  |  |  | 			'GID',  | 
					
						
							|  |  |  | 			'File Name', 'Parent Directory', 'Full Path', | 
					
						
							| 
									
										
										
										
											2016-04-21 01:42:06 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			'Date created', 'ctime', 'mtime', 'atime', | 
					
						
							| 
									
										
										
										
											2016-04-20 03:56:19 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			'Index (ribbon)', 'Index (crop)', 'Index (global)', | 
					
						
							| 
									
										
										
										
											2016-01-24 01:58:48 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-19 01:23:47 +03:00
										 |  |  | 			// metadata...
 | 
					
						
							| 
									
										
										
										
											2016-01-15 05:19:42 +03:00
										 |  |  | 			'Make', 'Camera Model Name', 'Lens ID', 'Lens', 'Lens Profile Name', 'Focal Length', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			'Metering Mode', 'Exposure Program', 'Exposure Compensation',  | 
					
						
							| 
									
										
										
										
											2016-04-01 18:42:45 +03:00
										 |  |  | 			'Shutter Speed Value', 'Exposure Time',  | 
					
						
							|  |  |  | 			'Aperture Value', 'F Number',  | 
					
						
							|  |  |  | 			'Iso', | 
					
						
							|  |  |  | 			'Quality', 'Focus Mode',  | 
					
						
							| 
									
										
										
										
											2016-01-15 05:19:42 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			'Artist', 'Copyright', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			'Date/time Original', 'Create Date', 'Modify Date', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			'Mime Type', | 
					
						
							| 
									
										
										
										
											2016-01-12 04:47:40 +03:00
										 |  |  | 		], | 
					
						
							| 
									
										
										
										
											2016-01-13 18:04:56 +03:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-24 00:05:58 +03:00
										 |  |  | 	toggleMetadataAutoSelect: ['Interface/Toggle metadata value auto-select', | 
					
						
							| 
									
										
										
										
											2016-03-28 22:07:38 +03:00
										 |  |  | 		core.makeConfigToggler('metadata-auto-select-mode',  | 
					
						
							| 
									
										
										
										
											2016-01-24 00:05:58 +03:00
										 |  |  | 			function(){ return this.config['metadata-auto-select-modes'] })], | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-13 03:05:25 +03:00
										 |  |  | 	// NOTE: this will extend the Browse object with .updateMetadata(..)
 | 
					
						
							|  |  |  | 	// 		method to enable updating of metadata in the list...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2016-01-15 05:37:06 +03:00
										 |  |  | 	// XXX should we replace 'mode' with nested set of metadata???
 | 
					
						
							| 
									
										
										
										
											2016-01-16 08:53:03 +03:00
										 |  |  | 	// XXX make this support multiple images...
 | 
					
						
							| 
									
										
										
										
											2016-05-14 22:50:26 +03:00
										 |  |  | 	showMetadata: ['Image/Metadata...', | 
					
						
							| 
									
										
										
										
											2016-05-04 21:28:46 +03:00
										 |  |  | 		widgets.makeUIDialog(function(image, mode){ | 
					
						
							|  |  |  | 		//function(image, mode){
 | 
					
						
							| 
									
										
										
										
											2016-01-24 00:05:58 +03:00
										 |  |  | 			var that = this | 
					
						
							| 
									
										
										
										
											2016-01-09 04:59:57 +03:00
										 |  |  | 			image = this.data.getImage(image) | 
					
						
							| 
									
										
										
										
											2016-01-15 05:43:37 +03:00
										 |  |  | 			mode = mode || 'disabled' | 
					
						
							| 
									
										
										
										
											2016-01-15 05:19:42 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			var field_order = this.config['metadata-field-order'] || [] | 
					
						
							|  |  |  | 			var x = field_order.length + 1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-19 05:38:48 +03:00
										 |  |  | 			// get image metadata...
 | 
					
						
							| 
									
										
										
										
											2016-04-13 01:17:53 +03:00
										 |  |  | 			var metadata = this.getMetadata(image) || {}  | 
					
						
							|  |  |  | 			var img = this.images && this.images[image] || null | 
					
						
							| 
									
										
										
										
											2016-01-19 01:23:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-24 01:58:48 +03:00
										 |  |  | 			// helpers...
 | 
					
						
							|  |  |  | 			var _cmp = function(a, b){ | 
					
						
							| 
									
										
										
										
											2016-04-20 03:56:19 +03:00
										 |  |  | 				a = field_order.indexOf(a[0].replace(/^- |: $/g, '')) | 
					
						
							| 
									
										
										
										
											2016-01-24 01:58:48 +03:00
										 |  |  | 				a = a == -1 ? x : a | 
					
						
							| 
									
										
										
										
											2016-04-20 03:56:19 +03:00
										 |  |  | 				b = field_order.indexOf(b[0].replace(/^- |: $/g, '')) | 
					
						
							| 
									
										
										
										
											2016-01-24 01:58:48 +03:00
										 |  |  | 				b = b == -1 ? x : b | 
					
						
							|  |  |  | 				return a - b | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-13 03:05:25 +03:00
										 |  |  | 			var _buildInfoList = function(image, metadata){ | 
					
						
							|  |  |  | 				// XXX move these to an info feature...
 | 
					
						
							|  |  |  | 				// base fields...
 | 
					
						
							|  |  |  | 				var base = [ | 
					
						
							|  |  |  | 					['GID: ', image], | 
					
						
							|  |  |  | 					// NOTE: these are 1-based and not 0-based...
 | 
					
						
							|  |  |  | 					['Index (ribbon): ',  | 
					
						
							|  |  |  | 						that.data.getImageOrder('ribbon', image) + 1 | 
					
						
							| 
									
										
										
										
											2016-01-19 04:45:52 +03:00
										 |  |  | 						+'/'+  | 
					
						
							| 
									
										
										
										
											2016-04-13 03:05:25 +03:00
										 |  |  | 						that.data.getImages(image).len], | 
					
						
							|  |  |  | 					// show this only when cropped...
 | 
					
						
							|  |  |  | 					['Index (global): ',  | 
					
						
							|  |  |  | 						that.data.getImageOrder(image) + 1 | 
					
						
							|  |  |  | 						+'/'+  | 
					
						
							|  |  |  | 						that.data.getImages('all').len], | 
					
						
							|  |  |  | 				] | 
					
						
							|  |  |  | 				// crop-specific stuff...
 | 
					
						
							|  |  |  | 				if(that.crop_stack && that.crop_stack.len > 0){ | 
					
						
							|  |  |  | 					base = base.concat([ | 
					
						
							|  |  |  | 						['Index (crop): ',  | 
					
						
							|  |  |  | 							that.data.getImageOrder('loaded', image) + 1 | 
					
						
							|  |  |  | 							+'/'+  | 
					
						
							|  |  |  | 							that.data.getImages('loaded').len], | 
					
						
							|  |  |  | 					]) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				// fields that expect that image data is available...
 | 
					
						
							|  |  |  | 				var info = ['---'] | 
					
						
							|  |  |  | 				if(img){ | 
					
						
							|  |  |  | 					// XXX should these be here???
 | 
					
						
							|  |  |  | 					var _normalize = typeof(path) != 'undefined' ?  | 
					
						
							|  |  |  | 						path.normalize | 
					
						
							|  |  |  | 						: function(e){ return e.replace(/\/\.\//, '') } | 
					
						
							|  |  |  | 					var _basename = typeof(path) != 'undefined' ? | 
					
						
							|  |  |  | 						path.basename | 
					
						
							|  |  |  | 						: function(e){ return e.split(/[\\\/]/g).pop() } | 
					
						
							|  |  |  | 					var _dirname = typeof(path) != 'undefined' ? | 
					
						
							|  |  |  | 						function(e){ return path.normalize(path.dirname(e)) } | 
					
						
							|  |  |  | 						: function(e){ return _normalize(e.split(/[\\\/]/g).slice(0, -1).join('/')) } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					base = base.concat([ | 
					
						
							|  |  |  | 						['File Name: ',  | 
					
						
							|  |  |  | 							_basename(img.path)], | 
					
						
							|  |  |  | 						['Parent Directory: ',  | 
					
						
							|  |  |  | 							_dirname((img.base_path || '.') +'/'+ img.path)], | 
					
						
							|  |  |  | 						['Full Path: ',  | 
					
						
							|  |  |  | 							_normalize((img.base_path || '.') +'/'+ img.path)], | 
					
						
							| 
									
										
										
										
											2016-04-20 03:56:19 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-21 01:42:06 +03:00
										 |  |  | 						['Date created: ', img.birthtime  | 
					
						
							|  |  |  | 							&& new Date(img.birthtime).toShortDate()], | 
					
						
							|  |  |  | 						['- ctime: ', img.ctime && new Date(img.ctime).toShortDate()], | 
					
						
							|  |  |  | 						['- mtime: ', img.mtime && new Date(img.mtime).toShortDate()], | 
					
						
							|  |  |  | 						['- atime: ', img.atime && new Date(img.atime).toShortDate()], | 
					
						
							| 
									
										
										
										
											2016-04-13 03:05:25 +03:00
										 |  |  | 					]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// comment and tags...
 | 
					
						
							|  |  |  | 					info.push(['Comment: ',  | 
					
						
							|  |  |  | 						function(){ return img.comment || '' }])  | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2016-01-15 05:19:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-13 03:05:25 +03:00
										 |  |  | 				info.push(['Tags: ',  | 
					
						
							|  |  |  | 					function(){ return that.data.getTags().join(', ') || '' }]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// build fields...
 | 
					
						
							|  |  |  | 				var fields = [] | 
					
						
							|  |  |  | 				Object.keys(metadata).forEach(function(k){ | 
					
						
							|  |  |  | 					var n =  k | 
					
						
							|  |  |  | 						// convert camel-case to human-case ;)
 | 
					
						
							|  |  |  | 						.replace(/([A-Z]+)/g, ' $1') | 
					
						
							|  |  |  | 						.capitalize() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// skip metadata stuff in short mode...
 | 
					
						
							|  |  |  | 					if(mode != 'full'  | 
					
						
							|  |  |  | 							&& field_order.indexOf(n) == -1){ | 
					
						
							|  |  |  | 						if(mode == 'short'){ | 
					
						
							|  |  |  | 							return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						} else if(mode == 'disabled') { | 
					
						
							|  |  |  | 							n = '- ' + n | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2016-01-15 05:37:06 +03:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2016-01-15 05:19:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-13 03:05:25 +03:00
										 |  |  | 					fields.push([ n + ': ', metadata[k] ]) | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// sort fields...
 | 
					
						
							|  |  |  | 				base.sort(_cmp) | 
					
						
							|  |  |  | 				fields.sort(_cmp) | 
					
						
							| 
									
										
										
										
											2016-01-15 05:19:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-13 03:05:25 +03:00
										 |  |  | 				// add separator to base...
 | 
					
						
							|  |  |  | 				fields.length > 0 && info.push('---') | 
					
						
							| 
									
										
										
										
											2016-01-15 03:40:52 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-13 03:05:25 +03:00
										 |  |  | 				return base | 
					
						
							|  |  |  | 					.concat(info) | 
					
						
							|  |  |  | 					.concat(fields) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-01-19 05:38:48 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-26 07:43:22 +03:00
										 |  |  | 			// XXX might be a good idea to directly bind ctrl-c to copy value...
 | 
					
						
							| 
									
										
										
										
											2016-05-04 21:28:46 +03:00
										 |  |  | 			var o = browse.makeList( | 
					
						
							|  |  |  | 					null, | 
					
						
							|  |  |  | 					_buildInfoList(image, metadata), | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						showDisabled: false, | 
					
						
							| 
									
										
										
										
											2016-03-27 20:07:48 +03:00
										 |  |  | 					}) | 
					
						
							| 
									
										
										
										
											2016-05-04 21:28:46 +03:00
										 |  |  | 				// select value of current item...
 | 
					
						
							|  |  |  | 				.on('select', function(evt, elem){ | 
					
						
							|  |  |  | 					if(that.config['metadata-auto-select-mode'] == 'on select'){ | 
					
						
							|  |  |  | 						$(elem).find('.text').last().selectText() | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 				// XXX start editing onkeydown...
 | 
					
						
							|  |  |  | 				.on('keydown', function(){ | 
					
						
							|  |  |  | 					// XXX Enter + editable -> edit (only this???)
 | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 				// path selected...
 | 
					
						
							|  |  |  | 				.open(function(evt, path){  | 
					
						
							|  |  |  | 					var editable = RegExp(that.config['metadata-editable-fields'] | 
					
						
							|  |  |  | 						.map(function(f){ return util.quoteRegExp(f) }) | 
					
						
							|  |  |  | 						.join('|')) | 
					
						
							| 
									
										
										
										
											2016-01-24 00:05:58 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 21:28:46 +03:00
										 |  |  | 					var elem = o.filter(path).find('.text').last() | 
					
						
							| 
									
										
										
										
											2016-01-24 00:05:58 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 21:28:46 +03:00
										 |  |  | 					// handle select...
 | 
					
						
							|  |  |  | 					if(that.config['metadata-auto-select-mode'] == 'on open'){ | 
					
						
							|  |  |  | 						elem.selectText() | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2016-01-24 00:05:58 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 21:28:46 +03:00
										 |  |  | 					// skip non-editable fields...
 | 
					
						
							|  |  |  | 					if(editable.test(path)){ | 
					
						
							|  |  |  | 						elem | 
					
						
							|  |  |  | 							.prop('contenteditable', true) | 
					
						
							|  |  |  | 							.focus() | 
					
						
							|  |  |  | 							.keydown(function(){  | 
					
						
							|  |  |  | 								event.stopPropagation()  | 
					
						
							| 
									
										
										
										
											2016-03-26 04:01:13 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 21:28:46 +03:00
										 |  |  | 								var n = keyboard.toKeyName(event.keyCode) | 
					
						
							| 
									
										
										
										
											2016-03-26 04:01:13 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 21:28:46 +03:00
										 |  |  | 								// reset to original value...
 | 
					
						
							|  |  |  | 								if(n == 'Esc'){ | 
					
						
							|  |  |  | 									// XXX
 | 
					
						
							| 
									
										
										
										
											2016-03-26 04:01:13 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 21:28:46 +03:00
										 |  |  | 								// save value...
 | 
					
						
							|  |  |  | 								} else if(n == 'Enter' && event.ctrlKey){ | 
					
						
							|  |  |  | 									event.preventDefault() | 
					
						
							| 
									
										
										
										
											2016-03-26 04:01:13 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 21:28:46 +03:00
										 |  |  | 									// XXX
 | 
					
						
							|  |  |  | 								} | 
					
						
							|  |  |  | 							}) | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 				.on('close', function(){ | 
					
						
							|  |  |  | 					// XXX
 | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			o.dom.addClass('metadata-view') | 
					
						
							| 
									
										
										
										
											2016-01-15 03:40:52 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 21:28:46 +03:00
										 |  |  | 			o.updateMetadata = function(metadata){ | 
					
						
							| 
									
										
										
										
											2016-04-13 03:05:25 +03:00
										 |  |  | 				metadata = metadata || that.getMetadata() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// build new data set and update view...
 | 
					
						
							|  |  |  | 				this.options.data = _buildInfoList(image, metadata) | 
					
						
							|  |  |  | 				this.update() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				return this | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-15 03:40:52 +03:00
										 |  |  | 			return o | 
					
						
							| 
									
										
										
										
											2016-05-04 21:28:46 +03:00
										 |  |  | 		})] | 
					
						
							| 
									
										
										
										
											2016-01-09 04:59:57 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-12 04:33:10 +03:00
										 |  |  | var MetadataUI =  | 
					
						
							|  |  |  | module.MetadataUI = core.ImageGridFeatures.Feature({ | 
					
						
							| 
									
										
										
										
											2016-01-09 04:59:57 +03:00
										 |  |  | 	title: '', | 
					
						
							|  |  |  | 	doc: '', | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-12 04:33:10 +03:00
										 |  |  | 	tag: 'ui-metadata', | 
					
						
							| 
									
										
										
										
											2016-01-09 04:59:57 +03:00
										 |  |  | 	depends: [ | 
					
						
							|  |  |  | 		'ui', | 
					
						
							| 
									
										
										
										
											2016-01-12 04:33:10 +03:00
										 |  |  | 		'metadata', | 
					
						
							| 
									
										
										
										
											2016-01-09 04:59:57 +03:00
										 |  |  | 	], | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-12 04:33:10 +03:00
										 |  |  | 	actions: MetadataUIActions, | 
					
						
							| 
									
										
										
										
											2016-01-09 04:59:57 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-17 05:02:37 +03:00
										 |  |  | // Load etdata on demand...
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2016-04-13 03:05:25 +03:00
										 |  |  | var MetadataFSUI =  | 
					
						
							|  |  |  | module.MetadataFSUI = core.ImageGridFeatures.Feature({ | 
					
						
							|  |  |  | 	title: '', | 
					
						
							|  |  |  | 	doc: '', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tag: 'ui-fs-metadata', | 
					
						
							|  |  |  | 	depends: [ | 
					
						
							|  |  |  | 		'ui', | 
					
						
							|  |  |  | 		'metadata', | 
					
						
							|  |  |  | 		'fs-metadata', | 
					
						
							|  |  |  | 	], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	handlers: [ | 
					
						
							| 
									
										
										
										
											2016-04-13 05:45:10 +03:00
										 |  |  | 		// Read metadata and when done update the list...
 | 
					
						
							|  |  |  | 		// XXX should we show what we can and wait for metadata load (current
 | 
					
						
							|  |  |  | 		// 		state) or wait and show everything in one go???
 | 
					
						
							| 
									
										
										
										
											2016-04-13 03:05:25 +03:00
										 |  |  | 		['showMetadata.pre', | 
					
						
							|  |  |  | 			function(image){ | 
					
						
							|  |  |  | 				var that = this | 
					
						
							|  |  |  | 				var reader = this.readMetadata(image) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 21:28:46 +03:00
										 |  |  | 				return reader && function(client){ | 
					
						
							| 
									
										
										
										
											2016-04-13 05:19:14 +03:00
										 |  |  | 					var data = client.options.data | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-13 05:45:10 +03:00
										 |  |  | 					// add a loading indicator...
 | 
					
						
							| 
									
										
										
										
											2016-05-04 21:28:46 +03:00
										 |  |  | 					// NOTE: this will get overwritten when calling .updateMetadata()
 | 
					
						
							| 
									
										
										
										
											2016-04-13 05:19:14 +03:00
										 |  |  | 					data.push('---') | 
					
						
							| 
									
										
										
										
											2016-05-23 01:17:18 +03:00
										 |  |  | 					data.push('...') | 
					
						
							| 
									
										
										
										
											2016-04-13 05:19:14 +03:00
										 |  |  | 					client.update() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-13 03:05:25 +03:00
										 |  |  | 					reader.then(function(data){ | 
					
						
							| 
									
										
										
										
											2016-04-13 05:19:14 +03:00
										 |  |  | 						client.updateMetadata() | 
					
						
							| 
									
										
										
										
											2016-04-13 03:05:25 +03:00
										 |  |  | 					}) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}], | 
					
						
							|  |  |  | 	], | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | * vim:set ts=4 sw=4 :                                                */ | 
					
						
							|  |  |  | return module }) |