Ticket #298 (accepted enhancement)

Opened 4 years ago

Last modified 2 years ago

Challenge/Response status in details view + Adjusted gems in networks view/Crack probability

Reported by: alchemyandthunder Owned by: gkruse
Priority: major Milestone: 0.4
Component: gui Version: r319
Keywords: patch, handshakes, cracking, probability, gui, radical Cc:

Description

They're both semi-related so I'm submitting one patch for this.

Here's what it does:

Renames the gems to gemRed.png, gemOrange.png, gemYellow.png, gemGreen.png (for organizational purposes). (Please clear the current gems and instead use the uploaded gems for consistency. I did sprite edits to them)

Adds gemYellow.png.

Cracked/open networks get a GREEN gem, WPA/LEAP networks with a 4-way handshake get a YELLOW gem, WEP networks with over 130,000 IVs get a YELLOW gem, WPA/LEAP networks with a challenge or response but no handshake get an ORANGE gem (appears that this recognition is broken, test with  this to debug/fix), WEP networks with 80k-130k IVs get an ORANGE gem, WPA/LEAP networks with no ch/re/handshake get a RED gem, WEP networks with under 80k IVs get a RED gem.

Displays the Challenge/Response? status in Details View. 4-way (if captured), None (if not captured), N/A if network is WEP or open. Definitely handy to have in details view.

Displays cracking probability in Details View. 4-way handshake suggests that the net is only "crackable". WEP (since wep-40 vs. wep-104 distinction is broken) under 20k IVs is "very bad", 20k-50k is "bad", 50k-80k is "ok", 80k-100k is "good", over 100k is "very good". Feel free to re-word those. ;)
If it's open or cracked, it tells you that it's open... Or cracked...

I also fixed the 2 rows that DerNalia erroneously added to the ShortTable. Either the rows in the ShortTable needed to be added or the number of rows didn't need to increase (the GUI tells you that we have an "unknown row").

Index: KisMAC.xcodeproj/project.pbxproj
===================================================================
--- KisMAC.xcodeproj/project.pbxproj	(revision 318)
+++ KisMAC.xcodeproj/project.pbxproj	(working copy)
@@ -480,9 +480,6 @@
 		69AF11960E4B29C500B1D770 /* WaveDriverUSBRealtekRTL8187.h in Headers */ = {isa = PBXBuildFile; fileRef = 69AF118E0E4B29C500B1D770 /* WaveDriverUSBRealtekRTL8187.h */; };
 		69AF11970E4B29C500B1D770 /* WaveDriverUSBRealtekRTL8187.mm in Sources */ = {isa = PBXBuildFile; fileRef = 69AF118F0E4B29C500B1D770 /* WaveDriverUSBRealtekRTL8187.mm */; };
 		69AF11990E4B29DC00B1D770 /* KisMAC80211.h in Headers */ = {isa = PBXBuildFile; fileRef = 69AF11980E4B29DC00B1D770 /* KisMAC80211.h */; };
-		69C987490E5023F000B0E6A8 /* greengem.png in Resources */ = {isa = PBXBuildFile; fileRef = 69C987460E5023F000B0E6A8 /* greengem.png */; };
-		69C9874A0E5023F000B0E6A8 /* orangegem.png in Resources */ = {isa = PBXBuildFile; fileRef = 69C987470E5023F000B0E6A8 /* orangegem.png */; };
-		69C9874B0E5023F000B0E6A8 /* redgem.png in Resources */ = {isa = PBXBuildFile; fileRef = 69C987480E5023F000B0E6A8 /* redgem.png */; };
 		6C03D77009B547F2005B2316 /* Growl.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6C03D76F09B547F2005B2316 /* Growl.framework */; };
 		6C03D77309B547F6005B2316 /* Growl.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 6C03D76F09B547F2005B2316 /* Growl.framework */; };
 		6C1D31C009F37BC70005A9F8 /* PrefsAdvanced.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C1D31BE09F37BC70005A9F8 /* PrefsAdvanced.h */; };
@@ -510,6 +507,10 @@
 		8D1107280486CEB800E47090 /* KisMAC_Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = 32CA4F630368D1EE00C91783 /* KisMAC_Prefix.pch */; };
 		8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
 		8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
+		D46A7DAB0EB487E4005354E3 /* gemGreen.png in Resources */ = {isa = PBXBuildFile; fileRef = D46A7DA70EB487E4005354E3 /* gemGreen.png */; };
+		D46A7DAC0EB487E4005354E3 /* gemOrange.png in Resources */ = {isa = PBXBuildFile; fileRef = D46A7DA80EB487E4005354E3 /* gemOrange.png */; };
+		D46A7DAD0EB487E4005354E3 /* gemRed.png in Resources */ = {isa = PBXBuildFile; fileRef = D46A7DA90EB487E4005354E3 /* gemRed.png */; };
+		D46A7DAE0EB487E4005354E3 /* gemYellow.png in Resources */ = {isa = PBXBuildFile; fileRef = D46A7DAA0EB487E4005354E3 /* gemYellow.png */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXCopyFilesBuildPhase section */
@@ -849,9 +850,6 @@
 		69AF118E0E4B29C500B1D770 /* WaveDriverUSBRealtekRTL8187.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WaveDriverUSBRealtekRTL8187.h; sourceTree = "<group>"; };
 		69AF118F0E4B29C500B1D770 /* WaveDriverUSBRealtekRTL8187.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WaveDriverUSBRealtekRTL8187.mm; sourceTree = "<group>"; };
 		69AF11980E4B29DC00B1D770 /* KisMAC80211.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KisMAC80211.h; sourceTree = "<group>"; };
-		69C987460E5023F000B0E6A8 /* greengem.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = greengem.png; sourceTree = "<group>"; };
-		69C987470E5023F000B0E6A8 /* orangegem.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = orangegem.png; sourceTree = "<group>"; };
-		69C987480E5023F000B0E6A8 /* redgem.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = redgem.png; sourceTree = "<group>"; };
 		6C03D76F09B547F2005B2316 /* Growl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Growl.framework; path = Resources/Growl.framework; sourceTree = "<group>"; };
 		6C1D31BE09F37BC70005A9F8 /* PrefsAdvanced.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PrefsAdvanced.h; sourceTree = "<group>"; };
 		6C1D31BF09F37BC70005A9F8 /* PrefsAdvanced.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = PrefsAdvanced.m; sourceTree = "<group>"; };
@@ -876,6 +874,10 @@
 		87FA06B80BF6C69B00A8F24C /* FSWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSWindow.h; sourceTree = "<group>"; };
 		87FA06B90BF6C69B00A8F24C /* FSWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FSWindow.m; sourceTree = "<group>"; };
 		8D1107320486CEB800E47090 /* KisMAC.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = KisMAC.app; sourceTree = BUILT_PRODUCTS_DIR; };
+		D46A7DA70EB487E4005354E3 /* gemGreen.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = gemGreen.png; path = KisMAC/Trunk/r318/Resources/Icons/gemGreen.png; sourceTree = SYSTEM_DEVELOPER_DIR; };
+		D46A7DA80EB487E4005354E3 /* gemOrange.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = gemOrange.png; path = KisMAC/Trunk/r318/Resources/Icons/gemOrange.png; sourceTree = SYSTEM_DEVELOPER_DIR; };
+		D46A7DA90EB487E4005354E3 /* gemRed.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = gemRed.png; path = KisMAC/Trunk/r318/Resources/Icons/gemRed.png; sourceTree = SYSTEM_DEVELOPER_DIR; };
+		D46A7DAA0EB487E4005354E3 /* gemYellow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = gemYellow.png; path = KisMAC/Trunk/r318/Resources/Icons/gemYellow.png; sourceTree = SYSTEM_DEVELOPER_DIR; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -987,9 +989,10 @@
 		0035333206A5DD5700AB4577 /* Icons */ = {
 			isa = PBXGroup;
 			children = (
-				69C987460E5023F000B0E6A8 /* greengem.png */,
-				69C987470E5023F000B0E6A8 /* orangegem.png */,
-				69C987480E5023F000B0E6A8 /* redgem.png */,
+				D46A7DA70EB487E4005354E3 /* gemGreen.png */,
+				D46A7DA80EB487E4005354E3 /* gemOrange.png */,
+				D46A7DA90EB487E4005354E3 /* gemRed.png */,
+				D46A7DAA0EB487E4005354E3 /* gemYellow.png */,
 				6C541AA80A72002F00B58A95 /* growl-ap-revealed.png */,
 				6C541AA90A72002F00B58A95 /* growl-wpa-challenge.png */,
 				6C541AAA0A72002F00B58A95 /* growl-wpa-response.png */,
@@ -1959,9 +1962,10 @@
 				691CF1B10E4CC47C0042B146 /* UsbVendorsRT73.plist in Resources */,
 				691CF1B20E4CC47C0042B146 /* UsbVendorsRT2570.plist in Resources */,
 				691CF1B30E4CC47C0042B146 /* UsbVendorsRTL8187.plist in Resources */,
-				69C987490E5023F000B0E6A8 /* greengem.png in Resources */,
-				69C9874A0E5023F000B0E6A8 /* orangegem.png in Resources */,
-				69C9874B0E5023F000B0E6A8 /* redgem.png in Resources */,
+				D46A7DAB0EB487E4005354E3 /* gemGreen.png in Resources */,
+				D46A7DAC0EB487E4005354E3 /* gemOrange.png in Resources */,
+				D46A7DAD0EB487E4005354E3 /* gemRed.png in Resources */,
+				D46A7DAE0EB487E4005354E3 /* gemYellow.png in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
Index: Sources/Controller/InfoController.mm
===================================================================
--- Sources/Controller/InfoController.mm	(revision 318)
+++ Sources/Controller/InfoController.mm	(working copy)
@@ -49,8 +49,10 @@
 	indexInjPackets,
     indexBytes,
     indexKey,
-	indexASCIIKey, // Added for potential real password by DerNalia
+	indexASCIIKey, 
     indexLastIV, 
+	indexChallegeResponseStatus,
+	indexCrackingProbability,
     indexEmptyLine2,
     indexLatitude,
     indexLongitude,
@@ -206,7 +208,70 @@
 				return (col) ? NSLocalizedString(@"ASCII Key", "table descriptoin") : [_n asciiKey];
             case indexLastIV:
                  return (col) ? NSLocalizedString(@"LastIV", "table description") : [_n lastIV];
-            case indexEmptyLine2:
+			case indexChallegeResponseStatus:
+				if ((encryptionTypeWPA == [_n wep]) || (encryptionTypeLEAP == [_n wep]))
+				{
+					if ([_n challengeResponseStatus] == 3)
+					{
+						return (col) ? NSLocalizedString(@"Handshake", "table description") : [NSString stringWithFormat:@"4-way"];
+					}
+					else
+					{
+						return (col) ? NSLocalizedString(@"Handshake", "table description") : [NSString stringWithFormat:@"None"];
+					}
+				}
+				else if ((encryptionTypeWEP == [_n wep]) || (encryptionTypeWEP40 == [_n wep]) || (encryptionTypeNone == [_n wep]))
+				{
+					return (col) ? NSLocalizedString(@"Handshake", "table description") : [NSString stringWithFormat:@"N/A"];
+				}
+			case indexCrackingProbability: //this could probably be cleaned up a ton, it's functional, though.
+				NSLog(@"key = %@", [_n key]);
+				if (encryptionTypeNone == [_n wep])
+				{
+					return (col) ? NSLocalizedString(@"Cracking chance", "table description") : [NSString stringWithFormat:@"Open"];
+				}
+				if ([_n key] == NSLocalizedString(@"<unresolved>", "Unresolved password"))
+				{
+					if ((encryptionTypeWPA == [_n wep]) || (encryptionTypeLEAP == [_n wep]))
+					{
+						if ([_n challengeResponseStatus] == 3)
+							{
+								return (col) ? NSLocalizedString(@"Cracking Probability", "table description") : [NSString stringWithFormat:@"Crackable"];
+							}
+						else
+						{
+							return (col) ? NSLocalizedString(@"Cracking Probability", "table description") : [NSString stringWithFormat:@"Handshake needed"];
+						}
+					}
+					if ((encryptionTypeWEP == [_n wep]) || (encryptionTypeWEP40 == [_n wep]))
+					{	
+						if ([_n uniqueIVs] <= 20000)
+						{
+							return (col) ? NSLocalizedString(@"Cracking Probability", "table description") : [NSString stringWithFormat:@"Very bad"];
+						}
+						if (([_n uniqueIVs] >= 20000) && ([_n uniqueIVs] < 50000))
+						{
+						return (col) ? NSLocalizedString(@"Cracking Probability", "table description") : [NSString stringWithFormat:@"Bad"];
+						}
+						if (([_n uniqueIVs] >= 50000) && ([_n uniqueIVs] < 80000))
+						{
+							return (col) ? NSLocalizedString(@"Cracking Probability", "table description") : [NSString stringWithFormat:@"OK"];
+						}
+						if (([_n uniqueIVs] >= 80000) && ([_n uniqueIVs] < 100000))
+						{
+							return (col) ? NSLocalizedString(@"Cracking Probability", "table description") : [NSString stringWithFormat:@"Good"];
+						}
+						if ([_n uniqueIVs] >= 100000)
+						{
+							return (col) ? NSLocalizedString(@"Cracking Probability", "table description") : [NSString stringWithFormat:@"Very good"];
+						}

+					}
+				}
+				if ([_n key] != NSLocalizedString(@"<unresolved>", "Unresolved password"))
+				{
+					return (col) ? NSLocalizedString(@"Cracking Probability", "table description") : [NSString stringWithFormat:@"Cracked"];
+				}
+			case indexEmptyLine2:
                  return @"";
             case indexLatitude:
                  return (col) ? NSLocalizedString(@"Latitude", "table description") : [_n latitude];
@@ -269,11 +334,11 @@
 
 - (int)numberOfRowsInTableView:(NSTableView *)aTableView {
     if([aTableView isEqualTo:aTable])
-        return 27;
+        return 29;
     else if([aTableView isEqualTo:aClientTable])
         return [aClientKeys count];
     else if([aTableView isEqualTo:aShortTable])
-        return 15;
+        return 13;
    return 0;
 }
 
Index: Sources/Core/WaveContainer.m
===================================================================
--- Sources/Core/WaveContainer.m	(revision 318)
+++ Sources/Core/WaveContainer.m	(working copy)
@@ -194,13 +194,15 @@
 - (NSString*) getImageForChallengeResponse:(int)challengeResponseStatus {
     switch (challengeResponseStatus) {
         case chreResponse:
+			return @"gemOrange.png";
         case chreChallenge:
-            return @"orangegem.png";
+            return @"gemOrange.png";
         case chreComplete:
-            return @"greengem.png";
+            return @"gemYellow.png";
         case chreNone:
+			return @"gemRed.png";
         default:
-            return @"redgem.png";
+            return @"gemRed.png";
     }
 }
 
Index: Sources/Core/WaveNet.mm
===================================================================
--- Sources/Core/WaveNet.mm	(revision 318)
+++ Sources/Core/WaveNet.mm	(working copy)
@@ -39,7 +39,7 @@
 #import "WaveWeakContainer.h"
 
 #define WEP_GEM_ORANGE_LEVEL  80000
-#define WEP_GEM_GREEN_LEVEL   130000
+#define WEP_GEM_YELLOW_LEVEL   130000
 
 #define AMOD(x, y) ((x) % (y) < 0 ? ((x) % (y)) + (y) : (x) % (y))
 #define N 256
@@ -1511,52 +1511,92 @@
 	NSImage *image = nil;
 	if (_cacheValid) return _cache;
 	
-	switch (_isWep) 
+	switch (_isWep)
     {
 		case encryptionTypeLEAP:
 			enc = NSLocalizedString(@"LEAP", "table description");
+			if(_password == nil)
+			{
+				if(_challengeResponseStatus == chreResponse)
+				{
+					image = [NSImage imageNamed:@"gemOrange.png"];
+				}
+				else if(_challengeResponseStatus == chreChallenge)
+				{
+					image = [NSImage imageNamed:@"gemOrange.png"];
+				}
+				else if(_challengeResponseStatus == chreComplete)
+				{
+					image = [NSImage imageNamed:@"gemYellow.png"];
+				}
+			}
+			else if(_password != nil)
+			{
+				image = [NSImage imageNamed:@"gemGreen.png"];
+			}
 			break;
 		case encryptionTypeWPA:     
 			enc = NSLocalizedString(@"WPA", "table description");
-            if(_challengeResponseStatus == chreResponse)
-            {
-                image = [NSImage imageNamed:@"orangegem.png"];
-            }
-            else if(_challengeResponseStatus == chreChallenge)
-            {
-                image = [NSImage imageNamed:@"orangegem.png"];
-            }
-            else if(_challengeResponseStatus == chreComplete)
-            {
-                image = [NSImage imageNamed:@"greengem.png"];
-            }
+            if(_password == nil)
+			{
+				if(_challengeResponseStatus == chreResponse)
+				{
+					image = [NSImage imageNamed:@"gemOrange.png"];
+				}
+				else if(_challengeResponseStatus == chreChallenge)
+				{
+					image = [NSImage imageNamed:@"gemOrange.png"];
+				}
+				else if(_challengeResponseStatus == chreComplete)
+				{
+					image = [NSImage imageNamed:@"gemYellow.png"];
+				}
+			}
+			else if(_password != nil)
+			{
+				image = [NSImage imageNamed:@"gemGreen.png"];
+			}
 			break;
 		case encryptionTypeWEP40:
 			enc = NSLocalizedString(@"WEP-40", "table description");
-            if( [self uniqueIVs] > WEP_GEM_ORANGE_LEVEL && 
-                [self uniqueIVs] < WEP_GEM_GREEN_LEVEL)
-            {
-                image = [NSImage imageNamed:@"orangegem.png"];
-            }
-            else if([self uniqueIVs] > WEP_GEM_GREEN_LEVEL)
-            {
-                image = [NSImage imageNamed:@"greengem.png"];
-            }
+            if(_password == nil)
+			{
+				if( [self uniqueIVs] > WEP_GEM_ORANGE_LEVEL && 
+					[self uniqueIVs] < WEP_GEM_YELLOW_LEVEL)
+				{
+					image = [NSImage imageNamed:@"gemOrange.png"];
+				}
+				else if([self uniqueIVs] > WEP_GEM_YELLOW_LEVEL)
+				{
+					image = [NSImage imageNamed:@"gemYellow.png"];
+				}
+			}
+			else if(_password != nil)
+			{
+				image = [NSImage imageNamed:@"gemGreen.png"];
+			}
 			break;
 		case encryptionTypeWEP:
 			enc = NSLocalizedString(@"WEP", "table description");
-            if( [self uniqueIVs] > WEP_GEM_ORANGE_LEVEL && 
-                [self uniqueIVs] < WEP_GEM_GREEN_LEVEL)
-            {
-                image = [NSImage imageNamed:@"orangegem.png"];
-            }
-            else if([self uniqueIVs] > WEP_GEM_GREEN_LEVEL)
-            {
-                image = [NSImage imageNamed:@"greengem.png"];
-            }
+            if(_password == nil)
+			{
+				if( [self uniqueIVs] > WEP_GEM_ORANGE_LEVEL && 
+					[self uniqueIVs] < WEP_GEM_YELLOW_LEVEL)
+				{
+					image = [NSImage imageNamed:@"gemOrange.png"];
+				}
+				else if([self uniqueIVs] > WEP_GEM_YELLOW_LEVEL)
+				{
+					image = [NSImage imageNamed:@"gemYellow.png"];
+				}
+			}
+			else if(_password != nil)
+			{
+				image = [NSImage imageNamed:@"gemGreen.png"];
+			}
 			break;
 		case encryptionTypeNone:
-            image = [NSImage imageNamed:@"greengem.png"];
+            image = [NSImage imageNamed:@"gemGreen.png"];
 			enc = NSLocalizedString(@"NO", "table description");
 			break;
 		case encryptionTypeUnknown:
@@ -1595,7 +1635,7 @@
     //if we didn't set the Gem yet, set it red here
     if(nil == image)
     {
-        image = [NSImage imageNamed:@"redgem.png"];
+        image = [NSImage imageNamed:@"gemRed.png"];
     }
 	
 	cache = [NSDictionary dictionaryWithObjectsAndKeys:

Attachments

crackingprobability.patch Download (16.3 KB) - added by alchemyandthunder 4 years ago.
THE patch.
gemGreen.png Download (487 bytes) - added by alchemyandthunder 4 years ago.
green
gemOrange.png Download (488 bytes) - added by alchemyandthunder 4 years ago.
orange
gemRed.png Download (469 bytes) - added by alchemyandthunder 4 years ago.
red
gemYellow.png Download (501 bytes) - added by alchemyandthunder 4 years ago.
yeller
password.kismac Download (1.8 MB) - added by alchemyandthunder 3 years ago.
The .kismac for cracking/testing

Change History

Changed 4 years ago by alchemyandthunder

THE patch.

Changed 4 years ago by alchemyandthunder

green

Changed 4 years ago by alchemyandthunder

orange

Changed 4 years ago by alchemyandthunder

red

Changed 4 years ago by alchemyandthunder

yeller

comment:1 Changed 4 years ago by alchemyandthunder

Please edit out the line: NSLog(@"key = %@", [_n key]);

comment:2 Changed 3 years ago by alchemyandthunder

  • Version changed from r315 to r319

Here is my current work. I need gkruse or pr0gg3d to figure out how to refresh the gem from yellow to green when the network is cracked. The gem will only refresh if the network is scanned right now. I tried the obvious ways but it doesn't want to compile for some reason.

I'm uploading my project folder zipped plus a .kismac file for cracking purposes.

"DontFUCKwithMYnet" should crack with 40bit Weak Scheduling.

Changed 3 years ago by alchemyandthunder

The .kismac for cracking/testing

comment:3 Changed 3 years ago by alchemyandthunder

 http://www.mediafire.com/download.php?jxmktyo1jqm

There's my zipped project folder.

comment:4 Changed 3 years ago by pr0gg3d

  • Owner changed from gkruse to pr0gg3d

Reviewing patch...

comment:5 Changed 3 years ago by pr0gg3d

  • Status changed from new to assigned

comment:6 Changed 3 years ago by gkruse

  • Owner changed from pr0gg3d to gkruse
  • Status changed from assigned to accepted

comment:7 Changed 2 years ago by gkruse

  • Milestone changed from KisMAC 0.22a to 0.4

Milestone KisMAC 0.22a deleted

Note: See TracTickets for help on using tickets.