diff --git a/js/app/views/EpnTapUI.js b/js/app/views/EpnTapUI.js
index d75e156..57710f2 100644
--- a/js/app/views/EpnTapUI.js
+++ b/js/app/views/EpnTapUI.js
@@ -157,6 +157,101 @@ Ext.create('Ext.data.Store', {
 	}
 });
 
+Ext.define('App.util.Format', {
+	override: 'Ext.util.Format',
+	'text': function(data) {
+		return '<p style="white-space: normal;">' + data + '</p>';
+	},
+	'link': function(data) {
+		return '<a href="' + data + '">data</a>';
+	},
+	'img': function(data) {
+		return '<img width="40px height="40px" src="' + data + '">';
+	},
+	'type': function(data) {
+		var productTypeDict = Ext.data.StoreManager.lookup('productTypesStore').data.map;
+		return '<p>' + productTypeDict[data].data.name + '</p>';
+	},
+	'size': function(data) {
+		var size = parseInt(data);
+		var txt = '';
+		if (isNaN(size)) {
+		} else if (size >= 1024*1024) {
+			txt = (size/(1024*1024)).toPrecision(3) + 'Go';
+		} else if (size >= 1024) {
+			txt = (size/1024).toPrecision(3) + 'Mo';
+		} else {
+			txt = size + 'Ko';
+		}
+		return '<p>' + txt + '</p>'
+	},
+	'date': function(data) {
+		return data; // TODO
+	},
+	'number': function(val) {
+		if(val < 0) {
+			return '-';
+		} else if(val >= 1000*1000) {
+			return (val/(1000*1000)).toPrecision(3) + 'm';
+		} else if(val >= 1000) {
+			return (val/1000).toPrecision(3) + 'k';
+		} else {
+			return val;
+		}
+	},
+	'format': function(data) {
+		var mimetypeDict = {
+			'application/fits': 'fits',
+			'application/x-pds': 'pds',
+			'image/x-pds': 'pds',
+			'application/gml+xml': 'gml',
+			'application/json': 'json',
+			'application/octet-stream': 'bin, idl, envi or matlab',
+			'application/pdf': 'pdf',
+			'application/postscript': 'ps',
+			'application/vnd.geo+json': 'geojson',
+			'application/vnd.google-earth.kml+xml': 'kml',
+			'application/vnd.google-earth.kmz': 'kmz',
+			'application/vnd.ms-excel': 'xls',
+			'application/x-asdm': 'asdm',
+			'application/x-cdf': 'cdf',
+			'application/x-cdf-istp': 'cdf',
+			'application/x-cdf-pds4': 'cdf',
+			'application/x-cef1': 'cef1',
+			'application/x-cef2': 'cef2',
+			'application/x-directory': 'dir',
+			'application/x-fits-bintable': 'bintable',
+			'application/x-fits-euro3d': 'euro3d',
+			'application/x-fits-mef': 'mef',
+			'application/x-geotiff': 'geotiff',
+			'application/x-hdf': 'hdf',
+			'application/x-netcdf': 'nc',
+			'application/x-netcdf4': 'nc',
+			'application/x-tar': 'tar',
+			'application/x-tar-gzip': 'gtar',
+			'application/x-votable+xml': 'votable',
+			'application/x-votable+xml;content=datalink': 'votable',
+			'application/zip': 'zip',
+			'image/fits': 'fits',
+			'image/gif': 'gif',
+			'image/jpeg': 'jpeg',
+			'image/png': 'png',
+			'image/tiff': 'tiff',
+			'image/x-fits-gzip': 'fits',
+			'image/x-fits-hcompress': 'fits',
+			'text/csv': 'csv',
+			'text/html': 'html',
+			'text/plain': 'txt',
+			'text/tab-separated-values': 'tsv',
+			'text/xml': 'xml',
+			'video/mpeg': 'mpeg',
+			'video/quicktime': 'mov',
+			'video/x-msvideo': 'avi'
+		};
+		return (data in mimetypeDict) ? '<p>' + mimetypeDict[data] + '</p>' : '<em>' + data + '</em>';
+	}
+});
+
 /**
 `EpnTapUI`: The view of the AMDA EPN-TAP module, allowing the user to query and display granules information from
 EPN-TAP services.
@@ -406,18 +501,6 @@ Ext.define('amdaUI.EpnTapUI', {
 	service granules.
 	*/
 	createServicesGrid: function() {
-		var nbResRender = function(val) {
-			if(val < 0) {
-				return '-';
-			} else if(val >= 1000*1000) {
-				return (val/(1000*1000)).toPrecision(3) + 'm';
-			} else if(val >= 1000) {
-				return (val/1000).toPrecision(3) + 'k';
-			} else {
-				return val;
-			}
-		};
-
 		var epnTapServicesGrid = new Ext.grid.Panel({
 			id: 'epnTapServicesGrid',
 			title: 'Services',
@@ -425,7 +508,7 @@ Ext.define('amdaUI.EpnTapUI', {
 			flex: 1,
 			columns: [
 				{text: 'Name', dataIndex: 'short_name', flex: 1},
-				{text: 'Nb res.', dataIndex: 'nb_results', width: 50, renderer: nbResRender}
+				{text: 'Nb res.', dataIndex: 'nb_results', width: 50, renderer: 'number'}
 			],
 			viewConfig: {
 				getRowClass: function(record, index) {
@@ -503,90 +586,6 @@ Ext.define('amdaUI.EpnTapUI', {
 	TODO: infinite scroll! http://docs.sencha.com/extjs/4.2.3/extjs-build/examples/grid/infinite-scroll-with-filter.html
 	*/
 	createGranulesGrid: function() {
-		Ext.define('App.util.Format', {
-			override: 'Ext.util.Format',
-			'text': function(data) {
-				return '<p style="white-space: normal;">' + data + '</p>';
-			},
-			'link': function(data) {
-				return '<a href="' + data + '">data</a>';
-			},
-			'img': function(data) {
-				return '<img width="40px height="40px" src="' + data + '">';
-			},
-			'type': function(data) {
-				var productTypeDict = Ext.data.StoreManager.lookup('productTypesStore').data.map;
-				return '<p>' + productTypeDict[data].data.name + '</p>';
-			},
-			'format': function(data) {
-				var mimetypeDict = {
-					'application/fits': 'fits',
-					'application/x-pds': 'pds',
-					'image/x-pds': 'pds',
-					'application/gml+xml': 'gml',
-					'application/json': 'json',
-					'application/octet-stream': 'bin, idl, envi or matlab',
-					'application/pdf': 'pdf',
-					'application/postscript': 'ps',
-					'application/vnd.geo+json': 'geojson',
-					'application/vnd.google-earth.kml+xml': 'kml',
-					'application/vnd.google-earth.kmz': 'kmz',
-					'application/vnd.ms-excel': 'xls',
-					'application/x-asdm': 'asdm',
-					'application/x-cdf': 'cdf',
-					'application/x-cdf-istp': 'cdf',
-					'application/x-cdf-pds4': 'cdf',
-					'application/x-cef1': 'cef1',
-					'application/x-cef2': 'cef2',
-					'application/x-directory': 'dir',
-					'application/x-fits-bintable': 'bintable',
-					'application/x-fits-euro3d': 'euro3d',
-					'application/x-fits-mef': 'mef',
-					'application/x-geotiff': 'geotiff',
-					'application/x-hdf': 'hdf',
-					'application/x-netcdf': 'nc',
-					'application/x-netcdf4': 'nc',
-					'application/x-tar': 'tar',
-					'application/x-tar-gzip': 'gtar',
-					'application/x-votable+xml': 'votable',
-					'application/x-votable+xml;content=datalink': 'votable',
-					'application/zip': 'zip',
-					'image/fits': 'fits',
-					'image/gif': 'gif',
-					'image/jpeg': 'jpeg',
-					'image/png': 'png',
-					'image/tiff': 'tiff',
-					'image/x-fits-gzip': 'fits',
-					'image/x-fits-hcompress': 'fits',
-					'text/csv': 'csv',
-					'text/html': 'html',
-					'text/plain': 'txt',
-					'text/tab-separated-values': 'tsv',
-					'text/xml': 'xml',
-					'video/mpeg': 'mpeg',
-					'video/quicktime': 'mov',
-					'video/x-msvideo': 'avi'
-				};
-				return (data in mimetypeDict) ? '<p>' + mimetypeDict[data] + '</p>' : '<em>' + data + '</em>';
-			},
-			'size': function(data) {
-				var size = parseInt(data);
-				var txt = '';
-				if (isNaN(size)) {
-				} else if (size >= 1024*1024) {
-					txt = (size/(1024*1024)).toPrecision(3) + 'Go';
-				} else if (size >= 1024) {
-					txt = (size/1024).toPrecision(3) + 'Mo';
-				} else {
-					txt = size + 'Ko';
-				}
-				return '<p>' + txt + '</p>'
-			},
-			'date': function(data) {
-				
-			}
-		});
-
 		var epnTapGranulesGrid = new Ext.grid.Panel({
 			id: 'epnTapGranulesGrid',
 			title: 'Granules',
--
libgit2 0.21.2