From 93ae945414a9511dfe5c396205cfccac1c40a153 Mon Sep 17 00:00:00 2001
From: Thomas Tanghus <thomas@tanghus.net>
Date: Sun, 6 May 2012 00:33:16 +0200
Subject: Contacts: Fix for leftcontent positioning in Android browser.

---
 apps/contacts/js/contacts.js | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

(limited to 'apps/contacts/js/contacts.js')

diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js
index 68a01174d83..19f709abff3 100644
--- a/apps/contacts/js/contacts.js
+++ b/apps/contacts/js/contacts.js
@@ -171,7 +171,7 @@ Contacts={
 				// Make sure proper DOM is loaded.
 				var newid;
 				if(id == undefined) {
-					newid = $('#contacts li:first-child').data('id');
+					newid = $('#leftcontent li:first-child').data('id');
 				} else {
 					newid = id;
 				}
@@ -184,9 +184,9 @@ Contacts={
 						}
 					});
 				}
-				if($('#contacts li').length > 0) {
-					//var newid = $('#contacts li:first-child').data('id');
-					//$('#contacts li:first-child').addClass('active');
+				if($('#leftcontent li').length > 0) {
+					//var newid = $('#leftcontent li:first-child').data('id');
+					//$('#leftcontent li:first-child').addClass('active');
 					$('#leftcontent li[data-id="'+newid+'"]').addClass('active');
 					$.getJSON(OC.filePath('contacts', 'ajax', 'contactdetails.php'),{'id':newid},function(jsondata){
 						if(jsondata.status == 'success'){
@@ -195,7 +195,7 @@ Contacts={
 							OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
 						}
 					});
-				} else if($('#contacts li').length == 0) {
+				} else if($('#leftcontent li').length == 0) {
 					// load intro page
 					$.getJSON(OC.filePath('contacts', 'ajax', 'loadintro.php'),{},function(jsondata){
 						if(jsondata.status == 'success'){
@@ -295,7 +295,7 @@ Contacts={
 								this.id = this.fn = this.fullname = this.shortname = this.famname = this.givname = this.addname = this.honpre = this.honsuf = '';
 								this.data = undefined;
 								// Load first in list.
-								if($('#contacts li').length > 0) {
+								if($('#leftcontent li').length > 0) {
 									Contacts.UI.Card.update(newid);
 								} else {
 									// load intro page
@@ -1412,7 +1412,7 @@ Contacts={
 			update:function(){
 				$.getJSON(OC.filePath('contacts', 'ajax', 'contacts.php'),{},function(jsondata){
 					if(jsondata.status == 'success'){
-						$('#contacts').html(jsondata.data.page);
+						$('#leftcontent').html(jsondata.data.page);
 						Contacts.UI.Card.update();
 					}
 					else{
@@ -1423,14 +1423,14 @@ Contacts={
 			},
 			// Add thumbnails to the contact list as they become visible in the viewport.
 			lazyupdate:function(){
-				$('#contacts li').live('inview', function(){
+				$('#leftcontent li').live('inview', function(){
 					if (!$(this).find('a').attr('style')) {
 						$(this).find('a').css('background','url('+OC.filePath('contacts', '', 'thumbnail.php')+'?id='+$(this).data('id')+') no-repeat');
 					}
 				});
 			},
 			refreshThumbnail:function(id){
-				$('#contacts [data-id="'+id+'"]').find('a').css('background','url('+OC.filePath('contacts', '', 'thumbnail.php')+'?id='+id+'&refresh=1'+Math.random()+') no-repeat');
+				$('#leftcontent [data-id="'+id+'"]').find('a').css('background','url('+OC.filePath('contacts', '', 'thumbnail.php')+'?id='+id+'&refresh=1'+Math.random()+') no-repeat');
 			}
 		}
 	}
@@ -1486,7 +1486,7 @@ $(document).ready(function(){
 		return false;
 	});
 
-	$('#contacts li').bind('inview', function(event, isInView, visiblePartX, visiblePartY) {
+	$('#leftcontent li').bind('inview', function(event, isInView, visiblePartX, visiblePartY) {
 		if (isInView) { //NOTE: I've kept all conditions for future reference ;-)
 			// element is now visible in the viewport
 			if (visiblePartY == 'top') {
@@ -1525,11 +1525,11 @@ $(document).ready(function(){
 	// Name has changed. Update it and reorder.
 	$('#fn').live('change',function(){
 		var name = $('#fn').val();
-		var item = $('#contacts [data-id="'+Contacts.UI.Card.id+'"]').clone();
-		$('#contacts [data-id="'+Contacts.UI.Card.id+'"]').remove();
+		var item = $('#leftcontent [data-id="'+Contacts.UI.Card.id+'"]').clone();
+		$('#leftcontent [data-id="'+Contacts.UI.Card.id+'"]').remove();
 		$(item).find('a').html(name);
 		var added = false;
-		$('#contacts li').each(function(){
+		$('#leftcontent li').each(function(){
 			if ($(this).text().toLowerCase() > name.toLowerCase()) {
 				$(this).before(item).fadeIn('fast');
 				added = true;
-- 
cgit v1.2.3


From f2ec68d40c20c571d3f864e31fd9ed555b7d21c1 Mon Sep 17 00:00:00 2001
From: Thomas Tanghus <thomas@tanghus.net>
Date: Sun, 6 May 2012 13:01:45 +0200
Subject: Revert "Contacts: Fix for leftcontent positioning in Android
 browser."

This reverts commit 93ae945414a9511dfe5c396205cfccac1c40a153.
---
 apps/contacts/css/contacts.css    |  4 +---
 apps/contacts/js/contacts.js      | 26 +++++++++++++-------------
 apps/contacts/templates/index.php |  6 ++++--
 3 files changed, 18 insertions(+), 18 deletions(-)

(limited to 'apps/contacts/js/contacts.js')

diff --git a/apps/contacts/css/contacts.css b/apps/contacts/css/contacts.css
index 0541f16b66c..3eb3144bf4b 100644
--- a/apps/contacts/css/contacts.css
+++ b/apps/contacts/css/contacts.css
@@ -3,6 +3,7 @@
 }*/
 #leftcontent { top: 3.5em !important; }
 #rightcontent { top: 3.5em !important; padding-top: 5px; }
+#contacts { background: #fff; width: 20em; top: 3.7em; bottom:3em; position: fixed; overflow: auto; }
 #bottomcontrols { padding: 0; bottom:0px; height:2.8em; width: 20em; margin:0; background:#eee; border-top:1px solid #ccc; position:fixed; -moz-box-shadow: 0 0 0 #000, -3px 0 7px #000; -webkit-box-shadow: 0 0 0 #000, -3px 0 7px #000; box-shadow: 0 0 0 #000, -3px 0 7px #000;}
 #contacts_newcontact { float: left; margin: 0.2em 0 0 1em; }
 #chooseaddressbook { float: right; margin: 0.2em 1em 0 0; }
@@ -29,8 +30,6 @@ textarea { width: 80%; min-height: 5em; min-width: 30em; margin: 0 !important; p
 dl.form { width: 100%; float: left; clear: right; margin: 0; padding: 0; }
 .form dt { display: table-cell; clear: left; float: left; width: 7em; margin: 0; padding: 0.8em 0.5em 0 0; text-align:right; text-overflow:ellipsis; o-text-overflow: ellipsis; vertical-align: text-bottom; color: #bbb;/* white-space: pre-wrap; white-space: -moz-pre-wrap !important; white-space: -pre-wrap; white-space: -o-pre-wrap;*/ }
 .form dd { display: table-cell; clear: right; float: left; margin: 0; padding: 0px; white-space: nowrap; vertical-align: text-bottom; }
-.propertycontainer[data-element="EMAIL"] > input[type="email"] { min-width: 19em !important; }
-.propertycontainer[data-element="TEL"] > input[type="text"] { width: 10em !important; }
 #address.form dt { min-width: 5em; }
 #address.form dl { min-width: 10em; }
 .droptarget { margin: 0.5em; padding: 0.5em; border: thin solid #ccc; -moz-border-radius:.3em; -webkit-border-radius:.3em; border-radius:.3em; }
@@ -103,5 +102,4 @@ input[type="checkbox"] { width: 20px; height: 20px; vertical-align: bottom; }
 .propertylist li > input[type="checkbox"],input[type="radio"] { float: left; clear: left; width: 20px; height: 20px; vertical-align: middle; }
 .propertylist li > select { float: left; max-width: 8em; }
 .typelist { float: left; max-width: 10em; border: 0; background-color: #fff; } /* for multiselect */
-.typelist:hover, .typelist:active { background:#fff; color:#333; border:1px solid #ddd; -moz-box-shadow:0 1px 1px #fff, 0 2px 0 #bbb outset; -webkit-box-shadow:0 1px 1px #fff, 0 1px 0 #bbb outset; box-shadow:0 1px 1px #fff, 0 1px 0 #bbb outset; -moz-border-radius:.5em; -webkit-border-radius:.5em; border-radius:.5em; outline:none; }
 .addresslist { clear: both; font-weight: bold; }
diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js
index 19f709abff3..68a01174d83 100644
--- a/apps/contacts/js/contacts.js
+++ b/apps/contacts/js/contacts.js
@@ -171,7 +171,7 @@ Contacts={
 				// Make sure proper DOM is loaded.
 				var newid;
 				if(id == undefined) {
-					newid = $('#leftcontent li:first-child').data('id');
+					newid = $('#contacts li:first-child').data('id');
 				} else {
 					newid = id;
 				}
@@ -184,9 +184,9 @@ Contacts={
 						}
 					});
 				}
-				if($('#leftcontent li').length > 0) {
-					//var newid = $('#leftcontent li:first-child').data('id');
-					//$('#leftcontent li:first-child').addClass('active');
+				if($('#contacts li').length > 0) {
+					//var newid = $('#contacts li:first-child').data('id');
+					//$('#contacts li:first-child').addClass('active');
 					$('#leftcontent li[data-id="'+newid+'"]').addClass('active');
 					$.getJSON(OC.filePath('contacts', 'ajax', 'contactdetails.php'),{'id':newid},function(jsondata){
 						if(jsondata.status == 'success'){
@@ -195,7 +195,7 @@ Contacts={
 							OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
 						}
 					});
-				} else if($('#leftcontent li').length == 0) {
+				} else if($('#contacts li').length == 0) {
 					// load intro page
 					$.getJSON(OC.filePath('contacts', 'ajax', 'loadintro.php'),{},function(jsondata){
 						if(jsondata.status == 'success'){
@@ -295,7 +295,7 @@ Contacts={
 								this.id = this.fn = this.fullname = this.shortname = this.famname = this.givname = this.addname = this.honpre = this.honsuf = '';
 								this.data = undefined;
 								// Load first in list.
-								if($('#leftcontent li').length > 0) {
+								if($('#contacts li').length > 0) {
 									Contacts.UI.Card.update(newid);
 								} else {
 									// load intro page
@@ -1412,7 +1412,7 @@ Contacts={
 			update:function(){
 				$.getJSON(OC.filePath('contacts', 'ajax', 'contacts.php'),{},function(jsondata){
 					if(jsondata.status == 'success'){
-						$('#leftcontent').html(jsondata.data.page);
+						$('#contacts').html(jsondata.data.page);
 						Contacts.UI.Card.update();
 					}
 					else{
@@ -1423,14 +1423,14 @@ Contacts={
 			},
 			// Add thumbnails to the contact list as they become visible in the viewport.
 			lazyupdate:function(){
-				$('#leftcontent li').live('inview', function(){
+				$('#contacts li').live('inview', function(){
 					if (!$(this).find('a').attr('style')) {
 						$(this).find('a').css('background','url('+OC.filePath('contacts', '', 'thumbnail.php')+'?id='+$(this).data('id')+') no-repeat');
 					}
 				});
 			},
 			refreshThumbnail:function(id){
-				$('#leftcontent [data-id="'+id+'"]').find('a').css('background','url('+OC.filePath('contacts', '', 'thumbnail.php')+'?id='+id+'&refresh=1'+Math.random()+') no-repeat');
+				$('#contacts [data-id="'+id+'"]').find('a').css('background','url('+OC.filePath('contacts', '', 'thumbnail.php')+'?id='+id+'&refresh=1'+Math.random()+') no-repeat');
 			}
 		}
 	}
@@ -1486,7 +1486,7 @@ $(document).ready(function(){
 		return false;
 	});
 
-	$('#leftcontent li').bind('inview', function(event, isInView, visiblePartX, visiblePartY) {
+	$('#contacts li').bind('inview', function(event, isInView, visiblePartX, visiblePartY) {
 		if (isInView) { //NOTE: I've kept all conditions for future reference ;-)
 			// element is now visible in the viewport
 			if (visiblePartY == 'top') {
@@ -1525,11 +1525,11 @@ $(document).ready(function(){
 	// Name has changed. Update it and reorder.
 	$('#fn').live('change',function(){
 		var name = $('#fn').val();
-		var item = $('#leftcontent [data-id="'+Contacts.UI.Card.id+'"]').clone();
-		$('#leftcontent [data-id="'+Contacts.UI.Card.id+'"]').remove();
+		var item = $('#contacts [data-id="'+Contacts.UI.Card.id+'"]').clone();
+		$('#contacts [data-id="'+Contacts.UI.Card.id+'"]').remove();
 		$(item).find('a').html(name);
 		var added = false;
-		$('#leftcontent li').each(function(){
+		$('#contacts li').each(function(){
 			if ($(this).text().toLowerCase() > name.toLowerCase()) {
 				$(this).before(item).fadeIn('fast');
 				added = true;
diff --git a/apps/contacts/templates/index.php b/apps/contacts/templates/index.php
index fadfb31c03b..79825067d82 100755
--- a/apps/contacts/templates/index.php
+++ b/apps/contacts/templates/index.php
@@ -3,9 +3,11 @@
 	var categories = <?php echo json_encode($_['categories']); ?>;
 	var lang = '<?php echo OCP\Config::getUserValue(OCP\USER::getUser(), 'core', 'lang', 'en'); ?>';
 </script>
-<ul id="leftcontent" class="leftcontent">
+<div id="leftcontent" class="leftcontent">
+	<ul id="contacts">
 		<?php echo $this->inc("part.contacts"); ?>
-</ul>
+	</ul>
+</div>
 	<div id="bottomcontrols">
 		<form>
 			<button class="svg" id="contacts_newcontact" title="<?php echo $l->t('Add Contact'); ?>"><img class="svg" src="<?php echo OCP\Util::linkTo('contacts', 'img/contact-new.svg'); ?>" alt="<?php echo $l->t('Add Contact'); ?>"   /></button>
-- 
cgit v1.2.3


From 65b9850e5339d12fb8c62e32742533bc8166e233 Mon Sep 17 00:00:00 2001
From: Thomas Tanghus <thomas@tanghus.net>
Date: Sun, 6 May 2012 22:24:36 +0200
Subject: Code cleanup.

---
 apps/contacts/js/contacts.js | 58 +++++++-------------------------------------
 1 file changed, 9 insertions(+), 49 deletions(-)

(limited to 'apps/contacts/js/contacts.js')

diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js
index 68a01174d83..44b29792206 100644
--- a/apps/contacts/js/contacts.js
+++ b/apps/contacts/js/contacts.js
@@ -168,14 +168,14 @@ Contacts={
 			honsuf:'',
 			data:undefined,
 			update:function(id) {
-				// Make sure proper DOM is loaded.
 				var newid;
 				if(id == undefined) {
 					newid = $('#contacts li:first-child').data('id');
 				} else {
 					newid = id;
 				}
-				if(!$('n')) {
+				// Make sure proper DOM is loaded.
+				if(!$('#card')) {
 					$.getJSON(OC.filePath('contacts', 'ajax', 'loadcard.php'),{},function(jsondata){
 						if(jsondata.status == 'success'){
 							$('#rightcontent').html(jsondata.data.page);
@@ -185,8 +185,6 @@ Contacts={
 					});
 				}
 				if($('#contacts li').length > 0) {
-					//var newid = $('#contacts li:first-child').data('id');
-					//$('#contacts li:first-child').addClass('active');
 					$('#leftcontent li[data-id="'+newid+'"]').addClass('active');
 					$.getJSON(OC.filePath('contacts', 'ajax', 'contactdetails.php'),{'id':newid},function(jsondata){
 						if(jsondata.status == 'success'){
@@ -210,8 +208,6 @@ Contacts={
 			},
 			doExport:function() {
 				document.location.href = OC.linkTo('contacts', 'export.php') + '?contactid=' + this.id;
-				//$.get(OC.linkTo('contacts', 'export.php'),{'contactid':this.id},function(jsondata){
-				//});
 			},
 			doImport:function(){
 				Contacts.UI.notImplemented();
@@ -249,7 +245,7 @@ Contacts={
 								if(!added) {
 									$('#leftcontent ul').append(item);
 								}
-								if(isnew) {
+								if(isnew) { // add some default properties
 									Contacts.UI.Card.addProperty('EMAIL');
 									Contacts.UI.Card.addProperty('TEL');
 									Contacts.UI.Card.addProperty('NICKNAME');
@@ -261,7 +257,6 @@ Contacts={
 							}
 							else{
 								OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
-								//alert(jsondata.data.message);
 							}
 						});
 						$('#contact_identity').show();
@@ -291,11 +286,10 @@ Contacts={
 									newid = newlistitem.data('id');
 								}
 								$('#rightcontent').data('id',newid);
-								//$('#rightcontent').empty();
 								this.id = this.fn = this.fullname = this.shortname = this.famname = this.givname = this.addname = this.honpre = this.honsuf = '';
 								this.data = undefined;
-								// Load first in list.
-								if($('#contacts li').length > 0) {
+								
+								if($('#contacts li').length > 0) { // Load first in list.
 									Contacts.UI.Card.update(newid);
 								} else {
 									// load intro page
@@ -313,7 +307,6 @@ Contacts={
 							}
 							else{
 								OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
-								//alert(jsondata.data.message);
 							}
 						});
 					}
@@ -321,7 +314,6 @@ Contacts={
 				return false;
 			},
 			loadContact:function(jsondata){
-				//$('#contact_communication').hide();
 				this.data = jsondata;
 				this.id = this.data.id;
 				$('#rightcontent').data('id',this.id);
@@ -508,7 +500,6 @@ Contacts={
 				}
 			},
 			saveProperty:function(obj){
-				// I couldn't get the selector to filter on 'contacts_property' so I filter by hand here :-/
 				if(!$(obj).hasClass('contacts_property')) {
 					return false;
 				}
@@ -569,7 +560,6 @@ Contacts={
 				}
 			},
 			addProperty:function(type){
-				//console.log('addProperty:' + type);
 				switch (type) {
 					case 'PHOTO':
 						this.loadPhoto(true);
@@ -617,7 +607,6 @@ Contacts={
 			deleteProperty:function(obj, type){
 				Contacts.UI.loading(obj, true);
 				var checksum = Contacts.UI.checksumFor(obj);
-				//console.log('deleteProperty, id: ' + this.id + ', checksum: ' + checksum);
 				if(checksum) {
 					$.getJSON(OC.filePath('contacts', 'ajax', 'deleteproperty.php'),{'id': this.id, 'checksum': checksum },function(jsondata){
 						if(jsondata.status == 'success'){
@@ -822,16 +811,13 @@ Contacts={
 										if(isnew) {
 											container.remove();
 										}
-										//Contacts.UI.showHideContactInfo();
 									}
 								},
 								close : function(event, ui) {
-									//alert('close');
 									$(this).dialog('destroy').remove();
 									if(isnew) {
 										container.remove();
 									}
-									//Contacts.UI.showHideContactInfo();
 								},
 								open : function(event, ui) {
 									$( "#adr_city" ).autocomplete({
@@ -848,9 +834,6 @@ Contacts={
 												},
 												success: function( data ) {
 													response( $.map( data.geonames, function( item ) {
-														/*for(var key in item) {
-															console.log(key + ': ' + item[key]);
-														}*/
 														return {
 															label: item.name + (item.adminName1 ? ", " + item.adminName1 : "") + ", " + item.countryName,
 															value: item.name,
@@ -865,9 +848,6 @@ Contacts={
 											if(ui.item && $('#adr_country').val().trim().length == 0) {
 												$('#adr_country').val(ui.item.country);
 											}
-											/*log( ui.item ?
-												"Selected: " + ui.item.label :
-												"Nothing selected, input was " + this.value);*/
 										},
 										open: function() {
 											$( this ).removeClass( "ui-corner-all" ).addClass( "ui-corner-top" );
@@ -892,9 +872,6 @@ Contacts={
 												},
 												success: function( data ) {
 													response( $.map( data.geonames, function( item ) {
-														//for(var key in item) {
-														//	console.log(key + ': ' + item[key]);
-														//}
 														return {
 															label: item.name,
 															value: item.name
@@ -1245,12 +1222,9 @@ Contacts={
 					  function(jsondata) {
 						if (jsondata.status == 'success'){
 							$(obj).closest('tr').remove();
-							//$('#chooseaddressbook_dialog').dialog('destroy').remove();
 							Contacts.UI.Contacts.update();
-							//Contacts.UI.Addressbooks.overview();
 						} else {
 							OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
-							//alert('Error: ' + data.message);
 						}
 					  });
 				}
@@ -1480,7 +1454,6 @@ $(document).ready(function(){
 			}
 			else{
 				OC.dialogs.alert(jsondata.data.message, t('contacts', 'Error'));
-				//alert(jsondata.data.message);
 			}
 		});
 		return false;
@@ -1507,9 +1480,6 @@ $(document).ready(function(){
 		}
 	});
 	
-	// NOTE: For some reason the selector doesn't work when I select by '.contacts_property' too...
-	// I do the filtering in the event handler instead.
-	//$('input[type="text"],input[type="checkbox"],input[type="email"],input[type="tel"],input[type="date"], select').live('change', function(){
 	$('.contacts_property').live('change', function(){
 		Contacts.UI.Card.saveProperty(this);
 	});
@@ -1523,7 +1493,7 @@ $(document).ready(function(){
 	});
 	
 	// Name has changed. Update it and reorder.
-	$('#fn').live('change',function(){
+	$('#fn').change(function(){
 		var name = $('#fn').val();
 		var item = $('#contacts [data-id="'+Contacts.UI.Card.id+'"]').clone();
 		$('#contacts [data-id="'+Contacts.UI.Card.id+'"]').remove();
@@ -1541,9 +1511,7 @@ $(document).ready(function(){
 		}
 	});
 
-	/**
-	 * Profile picture upload handling
-	 */
+	// Profile picture upload handling
 	// New profile picture selected
 	$('#file_upload_start').change(function(){
 		Contacts.UI.Card.uploadPhoto(this.files);
@@ -1594,30 +1562,22 @@ $(document).ready(function(){
 						OC.dialogs.alert(xhr.status + ': ' + xhr.responseText, t('contacts', 'Error'));
 					}
 				} else {
-					//alert(xhr.responseText);
 					OC.dialogs.alert(response.data.message, t('contacts', 'Error'));
 				}
-				// stop loading indicator
-				//$('#contacts_details_photo_progress').hide();
 			}
 		};
 	
 		fileUpload.onprogress = function(e){
 			if (e.lengthComputable){
 				var _progress = Math.round((e.loaded * 100) / e.total);
-				if (_progress != 100){
-					//$('#contacts_details_photo_progress').text(_progress + '%');
-					//$('#contacts_details_photo_progress').val(_progress);
-				}
+				//if (_progress != 100){
+				//}
 			}
 		};
-		// Start loading indicator.
-		//$('#contacts_details_photo_progress').show()();
 		xhr.open('POST', OC.filePath('contacts', 'ajax', 'uploadphoto.php')+'?id='+Contacts.UI.Card.id+'&imagefile='+encodeURIComponent(file.name), true);
 		xhr.setRequestHeader('Cache-Control', 'no-cache');
 		xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
 		xhr.setRequestHeader('X_FILE_NAME', encodeURIComponent(file.name));
-		//xhr.setRequestHeader("X_FILENAME", file.name);
 		xhr.setRequestHeader('X-File-Size', file.size);
 		xhr.setRequestHeader('Content-Type', file.type);
 		xhr.send(file);
-- 
cgit v1.2.3