Re: [Evolution-hackers] vcard 2.1 implementation



On Wed, 2005-01-26 at 07:10, JP Rosevear wrote:
> On Tue, 2005-01-25 at 12:28 +0100, Armin Bauer wrote:
> > Hi,
> > 
> > i was just wondering if anyone is working on the task to implement vcard
> > 2.1 support in e-vcard.c? If not i will work on this.
> 
> I don't know of anyone currently working on this, so feel free to take a
> crack at this.
> 

Here is the patch. It adds the capability to generate 2.1 cards, encode
and decode quoted-printable and fixes a bug. it still has some quirks
(for example len in quoted_decode and encode is ignored). i will keep
you updated when i improve this.

Attached is also a vcard that made the vcard parser run in a loop. thats
what the lp++; is for.

> > Did you think about making a vcard parsing library out of this? There is
> > currently no usable vcard lib.
> 
> Standalone you mean? I don't think we'd really thought about that much.
> 
> -JP
--- evolution-data-server-1.1.3/addressbook/libebook/e-vcard.c	2004-08-05 20:25:21.000000000 +0200
+++ e-vcard.c	2005-01-26 11:03:22.000000000 +0100
@@ -22,6 +22,7 @@
 
 #include <glib.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
 #include "e-vcard.h"
@@ -63,6 +64,9 @@
 size_t _evc_base64_decode_simple (char *data, size_t len);
 char  *_evc_base64_encode_simple (const char *data, size_t len);
 
+size_t _evc_quoted_decode_simple (char *data, size_t len);
+char *_evc_quoted_encode_simple (const unsigned char *string, int len);
+
 static void
 e_vcard_dispose (GObject *object)
 {
@@ -196,7 +200,7 @@
 	char *lp;
 
 	lp = *p;
-
+	
 	while (*lp != '\r' && *lp != '\0') {
 		gboolean s_matches = FALSE;
 		char *ls;
@@ -209,6 +213,7 @@
 
 		if (s_matches)
 			break;
+		lp++;
 	}
 
 	*p = lp;
@@ -303,12 +308,13 @@
 	EVCardAttributeParam *param = NULL;
 	gboolean in_quote = FALSE;
 	str = g_string_new ("");
+	
 	while (*lp != '\0') {
 		if (*lp == '"') {
 			in_quote = !in_quote;
 			lp = g_utf8_next_char (lp);
 		}
-		else if (in_quote || g_unichar_isalnum (g_utf8_get_char (lp)) || *lp == '-' || *lp == '_') {
+		else if (in_quote || g_unichar_isalnum (g_utf8_get_char (lp)) || *lp == '-' || *lp == '_' || *lp == '/') {
 			str = g_string_append_unichar (str, g_utf8_get_char (lp));
 			lp = g_utf8_next_char (lp);
 		}
@@ -423,7 +429,7 @@
 				break;
 		}
 		else {
-			g_warning ("invalid character found in parameter spec");
+			g_warning ("invalid character found in parameter spec: %c", lp[0]);
 			g_string_assign (str, "");
 			skip_until (&lp, ":;");
 		}
@@ -482,11 +488,11 @@
 				str = g_string_new ("");
 			}
 		}
-		else if (g_unichar_isalnum (g_utf8_get_char (lp)) || *lp == '-' || *lp == '_') {
+		else if (g_unichar_isalnum (g_utf8_get_char (lp)) || *lp == '-' || *lp == '_' || *lp == '/') {
 			str = g_string_append_unichar (str, g_utf8_get_char (lp));
 		}
 		else {
-			g_warning ("invalid character found in attribute group/name");
+			g_warning ("invalid character found in attribute group/name: %c", lp[0]);
 			g_string_free (str, TRUE);
 			*p = lp;
 			skip_to_next_line(p);
@@ -677,7 +683,6 @@
 e_vcard_new_from_string (const char *str)
 {
 	EVCard *evc;
-
 	g_return_val_if_fail (str != NULL, NULL);
 
 	evc = g_object_new (E_TYPE_VCARD, NULL);
@@ -690,7 +695,122 @@
 static char*
 e_vcard_to_string_vcard_21  (EVCard *evc)
 {
-	g_warning ("need to implement e_vcard_to_string_vcard_21");
+	GList *l;
+	GList *v;
+
+	GString *str = g_string_new ("");
+
+	str = g_string_append (str, "BEGIN:VCARD" CRLF);
+
+	/* we hardcode the version (since we're outputting to a
+	   specific version) and ignore any version attributes the
+	   vcard might contain */
+	str = g_string_append (str, "VERSION:2.1" CRLF);
+
+	for (l = evc->priv->attributes; l; l = l->next) {
+		GList *p;
+		EVCardAttribute *attr = l->data;
+		GString *attr_str;
+		int l;
+
+		if (!g_ascii_strcasecmp (attr->name, "VERSION"))
+			continue;
+
+		attr_str = g_string_new ("");
+
+		/* From rfc2425, 5.8.2
+		 *
+		 * contentline  = [group "."] name *(";" param) ":" value CRLF
+		 */
+
+		if (attr->group) {
+			attr_str = g_string_append (attr_str, attr->group);
+			attr_str = g_string_append_c (attr_str, '.');
+		}
+		attr_str = g_string_append (attr_str, attr->name);
+
+		/* handle the parameters */
+		for (p = attr->params; p; p = p->next) {
+			EVCardAttributeParam *param = p->data;
+			/* 5.8.2:
+			 * param        = param-name "=" param-value *("," param-value)
+			 */
+			gboolean has_name = FALSE;
+			attr_str = g_string_append_c (attr_str, ';');
+			if (g_ascii_strcasecmp (param->name, "TYPE")) {
+				attr_str = g_string_append (attr_str, param->name);
+				has_name = TRUE;
+			}
+			if (param->values) {
+				if (has_name)
+					attr_str = g_string_append_c (attr_str, '=');
+				for (v = param->values; v; v = v->next) {
+					char *value = v->data;
+					char *p = value;
+					gboolean quotes = FALSE;
+					while (*p) {
+						if (g_utf8_get_char (p) != '-' && !g_unichar_isalnum (g_utf8_get_char (p))) {
+							quotes = TRUE;
+							break;
+						}
+						p = g_utf8_next_char (p);
+					}
+					if (quotes)
+						attr_str = g_string_append_c (attr_str, '"');
+					attr_str = g_string_append (attr_str, value);
+					if (quotes)
+						attr_str = g_string_append_c (attr_str, '"');
+					if (v->next)
+						attr_str = g_string_append_c (attr_str, ',');
+				}
+			}
+		}
+
+		attr_str = g_string_append_c (attr_str, ':');
+
+		for (v = attr->values; v; v = v->next) {
+			char *value = v->data;
+			char *escaped_value = NULL;
+
+			escaped_value = e_vcard_escape_string (value);
+
+			attr_str = g_string_append (attr_str, escaped_value);
+			if (v->next) {
+				/* XXX toshok - i hate you, rfc 2426.
+				   why doesn't CATEGORIES use a ; like
+				   a normal list attribute? */
+				if (!strcmp (attr->name, "CATEGORIES"))
+					attr_str = g_string_append_c (attr_str, ',');
+				else
+					attr_str = g_string_append_c (attr_str, ';');
+			}
+
+			g_free (escaped_value);
+		}
+
+		/* 5.8.2:
+		 * When generating a content line, lines longer than 75
+		 * characters SHOULD be folded
+		 */
+		l = 0;
+		do {
+			if (attr_str->len - l > 75) {
+				l += 75;
+				attr_str = g_string_insert_len (attr_str, l, CRLF " ", sizeof (CRLF " ") - 1);
+			}
+			else
+				break;
+		} while (l < attr_str->len);
+
+		attr_str = g_string_append (attr_str, CRLF);
+
+		str = g_string_append (str, attr_str->str);
+		g_string_free (attr_str, TRUE);
+	}
+
+	str = g_string_append (str, "END:VCARD\r\n\r\n");
+
+	return g_string_free (str, FALSE);
 	return g_strdup ("");
 }
 
@@ -737,6 +857,8 @@
 			/* 5.8.2:
 			 * param        = param-name "=" param-value *("," param-value)
 			 */
+			if (!g_ascii_strcasecmp (param->name, "CHARSET"))
+				continue;
 			attr_str = g_string_append_c (attr_str, ';');
 			attr_str = g_string_append (attr_str, param->name);
 			if (param->values) {
@@ -1008,26 +1130,34 @@
 	g_return_if_fail (attr != NULL);
 
 	switch (attr->encoding) {
-	case EVC_ENCODING_RAW:
-		g_warning ("can't add_value_decoded with an attribute using RAW encoding.  you must set the ENCODING parameter first");
-		break;
-	case EVC_ENCODING_BASE64: {
-		char *b64_data = _evc_base64_encode_simple (value, len);
-		GString *decoded = g_string_new_len (value, len);
-
-		/* make sure the decoded list is up to date */
-		e_vcard_attribute_get_values_decoded (attr);
-
-		d(printf ("base64 encoded value: %s\n", b64_data));
-		d(printf ("original length: %d\n", len));
-
-		attr->values = g_list_append (attr->values, b64_data);
-		attr->decoded_values = g_list_append (attr->decoded_values, decoded);
-		break;
-	}
-	case EVC_ENCODING_QP:
-		g_warning ("need to implement quoted printable decoding");
-		break;
+		case EVC_ENCODING_RAW:
+			g_warning ("can't add_value_decoded with an attribute using RAW encoding.  you must set the ENCODING parameter first");
+			break;
+		case EVC_ENCODING_BASE64: {
+			char *b64_data = _evc_base64_encode_simple (value, len);
+			GString *decoded = g_string_new_len (value, len);
+	
+			/* make sure the decoded list is up to date */
+			e_vcard_attribute_get_values_decoded (attr);
+	
+			d(printf ("base64 encoded value: %s\n", b64_data));
+			d(printf ("original length: %d\n", len));
+	
+			attr->values = g_list_append (attr->values, b64_data);
+			attr->decoded_values = g_list_append (attr->decoded_values, decoded);
+			break;
+		}
+		case EVC_ENCODING_QP: {
+			char *qp_data = _evc_quoted_encode_simple (value, len);
+			GString *decoded = g_string_new (value);
+	
+			/* make sure the decoded list is up to date */
+			e_vcard_attribute_get_values_decoded (attr);
+	
+			attr->values = g_list_append (attr->values, qp_data);
+			attr->decoded_values = g_list_append (attr->decoded_values, decoded);
+			break;
+		}
 	}
 }
 
@@ -1279,7 +1409,14 @@
 			}
 			break;
 		case EVC_ENCODING_QP:
-			g_warning ("need to implement quoted printable decoding");
+			for (l = attr->values; l; l = l->next) {
+				if (!(l->data))
+					continue;
+				char *decoded = g_strdup ((char*)l->data);
+				int len = _evc_quoted_decode_simple (decoded, strlen (decoded));
+				attr->decoded_values = g_list_append (attr->decoded_values, g_string_new_len (decoded, len));
+				g_free (decoded);
+			}
 			break;
 		}
 	}
@@ -1614,3 +1751,56 @@
 	return _evc_base64_decode_step ((unsigned char *)data, len,
 					(unsigned char *)data, &state, &save);
 }
+
+char *
+_evc_quoted_encode_simple(const unsigned char *string, int len)
+{
+	GString *tmp = g_string_new("");
+	
+	int i = 0;
+	while(string[i] != 0) {
+		if (string[i] > 127 || string[i] == 13 || string[i] == 10 || string[i] == '=') {
+			g_string_append_printf(tmp, "=%02X", string[i]);
+		} else {
+			g_string_append_c(tmp, string[i]);
+		}
+		i++;
+	}
+	
+	char *ret = tmp->str;
+	g_string_free(tmp, FALSE);
+	return ret;
+}
+
+
+size_t
+_evc_quoted_decode_simple (char *data, size_t len)
+{
+	g_return_val_if_fail (data != NULL, 0);
+
+	GString *string = g_string_new(data);
+	if (!string)
+		return 0;
+
+	char hex[5];
+	hex[4] = 0;
+
+	while (1) {
+		//Get the index of the next encoded char
+		int i = strcspn(string->str, "=");
+		if (i >= strlen(string->str))
+			break;
+		
+		strcpy(hex, "0x");
+		strncat(hex, &string->str[i + 1], 2);
+		char rep = ((int)(strtod(hex, NULL)));
+		g_string_erase(string, i, 2);
+		g_string_insert_c(string, i, rep);
+	}
+	
+	memset(data, 0, strlen(data));
+	strcpy(data, string->str);
+	g_string_free(string, 1);
+	
+	return strlen(data);
+}
BEGIN:VCARD
ADR;TYPE=home;TYPE=pref:1234567890;;Foo Palace,\n173/A Foo Tower Road,\n98t
 h Precinct.\nLeave any parcels in the nook of the tree at the top of the ga
 rden next to the old Roman columns which are covered in poison ivy and have
  lots of spiders in them. Make sure you put the parcel in a sealed containe
 r to keep out the spiders and the rain. Leave a piece of bread for the bird
 s while you are there. The birds help keep the spiders under control and Fo
 o hates spiders.;Foosville;Foo Valley Heights;9876543210;Australia
ADR;TYPE=work:123;;This is Foo's work address.\n15 FooBar Tce,\nFooBar Town
 ;Bar Heights;Bartonia;1234;Australia
CLASS:PUBLIC
EMAIL;TYPE=PREF:foo bar com
EMAIL:foo bar org
FN:Foo Bar
GEO:-36.900002;149.399994
N:Bar;Foo;;;
NICKNAME:Nickname Foo
NOTE:This is a note and this is it's first line.\nThis is the second line o
 f the note.\nThis is the third line of the note.\nThis is the fourth line o
 f the note.\nThis is the fifth line of the note.\nThis is one very long lin
 e, it contains a whole lot of characters and its purpose is to test that lo
 ng lines are properly supported by any vcard reader or writer, this is done
  because some vcard readers balk at reading lines longer than seventy chara
 cters.\nThis is some "double quoted text".\nThis is some 'single quoted tex
 t'.\n\nAbove is a blank line.\nHere are some punctuation characters ~`! #$%
 ^&*()_+=\|[{]};:'",<.>/?.\nAnd this is the very last line of the note.
ORG:Fooo Fab International
PHOTO;ENCODING=b;TYPE=image/png:iVBORw0KGgoAAAANSUhEUgAAAGQAAABLCAIAAAAJerX
 gAAAgAElEQVR4nEy5Z7yeVZX+v/bed7+fXs55Tj8npyU5CSEkARJIIHSkd2cEGUUdwDK2gRFRUU
 dHRwdnBKXoKKhDUxQp0kInjXRO2sk5Ob0+vdz93uX3Aj+f/3+93G/W9bnWWvvF90J9bbB+w1CuT
 c82JU6OTaxcu6qSd1joeJzmi/oTT70DSBiBxrHkERcD4wwAAWDISPFiUAMprfn1T16AmzO+CACH
 CFFgniBYBdfHCIgqF3w1wkO85FuZzHBdbB+tchBUcCwAAwoJBgAOAAgAgIAALogAABBYUAGCgw7
 QEonc1lCXUMOHoBWBIWAKAxbQypVAQw7nHAQXVCcoIqm+CEFiCEHggqlosZyYbknlnIXxbOYXbx
 cRk0Uo9Cy948ufm5s9mc0kCkvzXV0517UIVYaGhhbnp+MKikUihVr1W/f+kVPsUxlhKq3fsMowV
 MuyMGHRaLRWbViWq0gik80cGh4jgDgSFDgXFATTKJaQJhHZDp1iGOgx1auXWiRY3dNctvIMC4wx
 wsAJB8EJwQgEAGQ14dV9FMNTZWe66IUCcQDOgQFgAJ1iAAAADgIAfIIRQhwBQggxSrDgiHMODdv
 7EbLOIHgDRCh1isCTQiohmocg6ktAAEAIAYAQMO6GrCOXrNcrjEE0Fa1qZYP6DQJ4yWY+aKqCkD
 j/gjMLhaX+nj7GQqNDt2vV9tbu/v5+L/AXlgpyc1L2fUIIxgAYCyEQgDS4vPP48eOKJnxPWlyaT
 4bhso7BQn6mXK68884IEZgICAjoyEspwFRue47LQRCIo/DTF/RpQUnilZDlMUgICUQQQsBBICo4
 5VggAUIq2Mm0/PZ8dNtYJSCYEQEcEMECgCNhf7RF8PfVUn0uADEEAoALRrCCCQolXGCiCcnbuLs
 NrLWqlsXaZup1MXmGuBXBdSoECAAALjhlekJaXKwQCRJZtcGKZiaaUURJwMS8qRDkuRyQ29KRWV
 iaTxmCIOxY7mDfgGU547Nzu3buHVq5XNUFRdwwDE0D3yUAAgAkP6z1DXTkl4oYSwMDA4eOnuhq7
 Ucgt7d1KvIO6nAZIFBEl4KWR7Q1SYbVgCNIpg2tGSZPjLX3KJYG+TBrBBXOBUIAGBjmsiQYABMC
 C4C29j1j829NVFysAw+jQA0gMmCKhIt4zgcMSAIkAUIAQkbABeYCACoKdoMgBHAwOAB5rBLJULk
 44QfHwZ8n4gJuyqAWJD/LEQACJAIAwrlfF3FVlglDjCFVqFP1EQMSqbbfnJhTQimbytpA+wf72t
 vb84sjkqQEoiEb7NQVfZyYph45uO9g+6o2w5CshosxIIT+btZSfi4RT3V0dCwuzSmK0t/fb1lWJ
 BIBAN8HCYEkAIDHAeewZOnECQOOgILb5AgugQ8KF4FsuyAEEoAwEoIhBJggrAFQHArYuwTHi9xm
 ABKHkCUJMgWSEaIADkY6AwIgC5ARQgIU8BWEVYyIQHEkXIAQoI5QRQjKpIrkO5LIhiQO8hh4MnI
 6BG5miAEG4ICAAYQCcSokInMIfcTjzToQwL73+nQFQpAkqNXLzAgJIYl4OnC7ypV8d8+Q47HRsa
 lyuTw3V2ptag0D12WUMVmIj84bAABrSrpRDzKZDMZkemrh1mv+ybPqbmAXy3UgIBHEAYBJUU2V3
 IZEEfEhIkCqgM+jmgL1gqWxiExsjDETjLJQ05FgAAjHsIioeNe8tu3Q7EkLhIZTwl+jyu2UaGEo
 eIgEBY9OKWyawCKSJng4KryaMCSsEcYkTuOBaAZoxzBIxDoCW0TQyRhwVEV6HgzM8QFJvEjYuKL
 YiAUIES4FXFQl7mkQ+E7ah4yH8gfdXx9x75sSL885SVV3KTUiZkumaWm+cuLE7KGThdCnhPsI6I
 nFvBmJMR5U6gXO5GIpANlQo8CQTyTQogoZ6DUxRmEYJJLxer1eWCrMLEzbjqvrZk9X/NDBRQRAd
 c30nI6WmFduJKKY+iKWNOoNOxXTrQbFJJBkIpvIc1lMifoWMkiMoPBoSdoxGeybDmxCEIOWUOpH
 JBYGuuBxIAmOkxzlsBQNBeKsKIVcAyQjh4fFMPQwVAmEQgtAcIEMJgwOcZlvCKUBhueIU5ZdhjA
 QBTFhUZqWJVdwSXAZECDoDiWElCWFWhgZWIooke4gYtFgiUnxqFqrNRzf6ujJFouV7t5+RP2NZ5
 7puAGlWJd1RkVTczKT0AxDPjh87I1t07qmui7lSMKGYXieZ5qm4zjJZNKjTiwWUxSNMZZKxBAgC
 hLhYAvIhyxwwJB1CUBVNB6CjImgQAABF4hoLASCPUMXIdQdHw0vhoeXoEElgQAwSgCOAqiYMACM
 AAMjwDQBTAGQIM6g1xErHJEligRQwbCEUBnxCog6iAARDDAuQRnROMA6RjaGQATCDAEiZYA5Ssu
 AKSEcBBbggOJDmFSVZFTzZXpKNnZeOrZMY8Ad27YBcDSSaG9vX75iIG4a1113gx/wU9esUyR1am
 pmZmZucHCwVM7HE2Y6nY6Y4DoBAJi6gU3TBIBqtTo7O5vP56+96WrV0Mul6uLsvOdUKBJmPM08d
 yGA3WVgpgJIIRjqVkNgsFyHKCBrakBZqeBkkqrDw0DnRYX+Zb9/YIZXmAkCZzi0EqIjv8CCJc4c
 GdUUVCOogkRBBMsCWEZJK1EBgQfQ5vEcVkxMNEwwD1zgNSwKkihgMuAaS0L6QAo8CSeI2ssBUU9
 ImOrKQQEjGFyVMAAMZAqcCLB2h+Rc1GQQJShCbeLmFamVccSYiJiRSrHW29t71tkbKsUZzdRk3Z
 iYmsGcnX32pptuuuH48ePLB4cq5UYikSQYaIij0WhTVJGKxaJt29FotFItxWKxplw629zU1Nw22
 D/w1+ee6upNTJ2sqljyBJuto0UcmOUgppPAC5kBDEMyqwXAJUNRacAYlCuJw/vqH85Ki0KRgCqh
 G5H45kBhQEOCfE2xQyBMhCGViYwI8mjwtsxVCs1MiqumhPAYbygU+iRD9cK4JC/w0AagnFAO45L
 TzKCXQgAhBSAgLypSlflyAKERK4Zu3glaZAyhaAbyelZ7rWibNbjKjPbXWEOBvplypkoURTDGFS
 2ybt26nz94/xWXX7L/0AemaV5w3jn282VAPsJw6SWXffDONtOIIs9yHJAlzXGcQKqRC89b6bqOG
 VFbWlpKxZrnmgf37fj8v94ud0YQg4cf+vYtn73s8Yef90JhNmknK75FkZFqymrYq/rxhNAiSMjY
 9zQ7NJ5603n9hDfnafVAyEIkCTTJeBkDm3CKkcYJ4pwAMwE7gjYQ84AiIVKyRogIMdMDpoSsjYs
 UQEsgDAESB0kIAyDFeQsgjhAgcAA4AoEhIiDGkIpwkWCZQUhEnbMBrEs8iEe1jMLbAS3qsKOubI
 zqbb5fZeIdKoqhSKbi9Xol2RRlImjKpVetWBc1M3/981/O2HjKfKFuWe7ePbva29ocP6zX7SPDU
 34QBEHwxwfvwbZtY4yFEJZlmaYJvhY3Eo2add/3/2uxqI6PHJqaPMCoC4DtoptLtReYOlyw90zX
 zZgqGUmkpWeX+J7h+otvVFxseFS1bDDMhAJBExdZhgmAGYJMhY84BYEBpUCJI0nFgDH4GCzmaQC
 5gHcK3IPVKJEMhCUQBKgGzCQoImGVAACLgUhIKhbgC/CQhACistrCZF1wKigixBdgIYEAyr7rlb
 xWR8rUuaANC8eE0GIKYASJeCqfz8eSkTPPPD0Mw55lXbZdNyPyipX90zOTqqq6rnvLLbeUy+VcL
 heNRhkTvhdKEp5dKkpBEKRSKUKI53mqYk41Js46Y2Wbhr95+c03X37vlWf/b35+7vNfuuDBR7b5
 BGaKM7GWtsP1xgkbjhb9xBzV4/GxGV60ZF01HdsF8E0EEctt0nC7hzj1LAQSSBTAxUICrAg0yyw
 GEOOEIEy4qKsowlAMcQuFdRRGKeaIc8AcACFEGAcGHABjSAgR+J6OpBIiLqOjhOvgZ5GyjKJhEi
 pItQGPcZYGKCnmH7hNBGUcDA49bC7C/AWEZkLh1+qZTKbmFaMxva+vb2Z6TpVVz7eGhw/29Xcyo
 GeeeebExARj7P3335dl3XV9QmQsEUlXSXOGJhJxP3ApZb4fLpYmUFVEtWau6MkU/MMXf/benj37
 3hunPjzy6+9dd+dZz/zyJROjkKgWyFUq5+u87oIQCFSMQmd9KnKKabQ5nkyFC8wFsACXZOYirnN
 CBPJBaJJMEEYYAQJXsDBkPmMIgUpAAihgYmHAHHsANhYhwhwQRgQBqWOOBALALqICCROpNg0LEK
 ZkaYlzEnCqRCzmDCraJhd2AWrzzSGkfSGacoV1JORPh6SCiaAonU5+8aufGp8auf2OOybGZ1asW
 FEoFJcPDNZrTsiYqijb338nnYgLIaKR5PPP7eIcUcquO2c5XlqqNBoN27YZY0KICzefW1iw2ztX
 3ffgQzPI/t5PvlhaBM/DhiJ96pZvt/bF2pqxTH3OKaWUeq5rWbLwoxoPXdsgCFmeKDsdYCgAAmO
 sm0hVaxhcDFgIEJxxroaMMBoy1gBaRkIHXUUKBhyhkGLgEhQgFAAEgGwQFCOQJMCECeEjwKoqQG
 AuCIYck5qJDhqEwAgAAo4k2eLACToObiERTkF1UlT38PmTNXTYkSY9FDX0WCQ2NzfHGL3pppt++
 ctfzs4s/uZ/HyOEJBNp04j+4Q9/KBQKlUplw4YNsiw7jqsoKGJGAMBpVKXRk0o6h1evkGNKe61R
 m3rxpQtzPTt//u1PtJt+cWkev/XKjrsvOfPHvk2QDH2x2AzlktSsKku+DxirMc1wXL/he4l4RFL
 UEds+FDg5Q6gOjgFRAz8HqItLFJCDGRegCvAJYCwbAAZAViEBZQxBOeQVAAkgRUULQQpiHMCWCQ
 QMCQYIh8AJkVjoEYICRGwBNewZILVSJQAaE7gOnHFHAjgk2AaCT6+QD4BNA3mqEXIRCsAyaI2aF
 4k1tpy3olAejyfMcrk43TipEKmwNPfk4/+bSiXacsn9B3euXnva7Fxlw/otX//aXUFAGLWJRM1M
 C6GMVSvlnq7manVJNbTxcnFZS0dPT1+htBhVZT676Czl7/vhjzpbO99/e5e8uHvV+Rfs2Xc4aDA
 ZaUHoMxHGdY26HtB4rVH1mc8Q1EK5ZEJV8JoAV2BZBYRRkmITkIwxxSigIQjBOfdouMCZw1lEIU
 kkTA51wWXOFQBMMONC5UgGJAEigGKcKQI4Ij5jSIg5TOYZn+NiBkkVGXyEFFACASUDT/CwJHDIO
 ZGASkIjEQCEiDd0SvvFl56um3J7V/vUzPRp6049euTouVvOmZyc6O/t9Ty3s2OQMZzPLzRqC3v3
 vfe3F47KkhmGnqzg01c0SQKgVhW+izUDq7rSNtg/WywuTM+WGkvnbT5LhDT0iYSdXLOa0uDS868
 +piq6EnBTVsJmjgoBcwqNui6DpjQ0QwmY2rAdRddDansC+cAbBEjADAAVFAUBA4ExwYAwxgghRr
 kKBIDJVGAOCECXJYlSjBBg1BRyDMAAXBAMICqgAbhEpCnBHAELQC0MIQJBMAAHQCC4QOAxschA/
 jtP5IAgCC3OYWAgl8zIRAI/cFpa2s45/7z//OmPk8nkhg0bgtA7OTLS1dWVzrQXSuV8YXZwsIeF
 VnOTOTsdChCSpOiKgjq62msl+6wNHQMrWd0KsY57HdkEKYgoAaO6qs3MzF3xtU+O7R49s2dtbPX
 QYu1dbJlmYvnWc2785s8+l+jUKSptXLu+wpyPbbinPqkAIMC+iolARCAIBVc5JYBiBOUYigokcU
 rQ34EfIaRKQw6gylKUKJJABmUm8whAAFDWwECSxAEYx7LEKJ/h5KSECyKknBGkUMwRQioAhpCBY
 BwwSIhiJmGBBQ1DCWFBOZYJpaGiwbnnnyLJbld37+VXfnxsamLF0PL/+8Nv8wuL0ZgpI3T99de+
 +/6OfKF6551feGfbs75bf/h/3qiUEeMeB/bCL7+AEllULQoJ6zdc39mSjMQjkYla1QzJynRmMmK
 Fiw72AQwdS35EInp7UwA8nU5fvPX8qUrdRIs0HjQyUftA3ZdnMtpFl2z+rAhBBPDdb9w46hSefP
 IttdYk4woAF8BsC2KRdMouZWU1FYQGiCwoH4KPMAhCQoEFAh6GKwByABwAo9hu5E0aYkbQHhsVz
 UjDtgAAK3I0Gg1KRQJw6yevuPH6KztaeznniUTihRdeWLNmTTqVOnjoyNe/fm+1btth4ID8EVtE
 EpJV2t6Z/s4P7nj6T0+ftvbMsBE25xIfDu/PZJK9vX2z+eCur9/94P33Mo/yULrvu09IAkAzdRX
 9/r6PE8VJIXCJRJlvJLMGpTXNUDRO24r1ZXlbzqU8YNH2Fh4wVTJCQoJQWA332JGRyZMTe7cPHz
 o40dndu+2lZ8/uvuKWy+76wpfO/vVv/nX5qZQBO+fa3i//2w3M93e/Mx2JNNVrwCFQ9GApFA0Jl
 xArEFTQSAeVJUFszi3BPcFdARZgBDoC7USTHbVoPOAIGeMQEKIS4IjT3z58/3/cd8/FF2zceu6Z
 pmmeu2XrwQMHn3nmmU2bNvm+Pzs7a5omxth2a8/+5amOjuya1QNuvZjPlwwF+z6rV5w/P/XOBRd
 e8sQfnmhpMfKF+e7uzjCAmz/x2WK58ptf/aq1LZlKtjz6yOO1GhUcGBOh7111/mkkCv7ll596ZH
 SxUAiSKSNjckmTBA3ijHWohpuIyOmYxcLKQiUSiUYSUc00gyCwq/XQdZubusxIZuWKgY722Pjhh
 Zf/9uE1t6yT4x42xccuvHGmcmBs7GjKaHvtpT2W3dDUWDQW8QMv5MAxDgE8DA7GUsgbwH2EkCwR
 ItU5nVHEBAnHcdAhRCSQIkpyEtMahFggFvq/efhnhsy3vfzilq2b39j2Bg9DRVJefe0Vyuju3bs
 mJye2nrd1Wc+ykdHjtlN/9bWXh48cUAh86tabzz/v3Beef1XWJAlrgmkf7N5r1cW1N2xpacktLC
 wuLpQXFypvvPn68oHBUmn2xNHpHdtHBUeMARDJkNiFZ60iX7t7k8Wnzty89sQxe2RkallHOhOJW
 8ybN/gZl1x85rnnmq2pxQ+Prx06xcEcY1St1xKx+JnrN5y76Yxdhz/0bEdynGx/R7IVP/yL7V/5
 wcfVtLx9z8z4gckrL7+6vGCjgLQvgxs/cc5LL3+QSBiVkqfLMhGIc0Q58pmY0uiCJFyEBEAgoMx
 YHENTCGkOzYE8DngHswoalz3R25aYGjnU05bp7Wxe1t3OOXr7jTeuuvKKMzasP+vsTYzRZct6zj
 tv65tvvvG73/3mc//82f0H9nV2d9555xeGD+ze/v7bldLSWRvXRRKRq6+6bPTEMSG4RPBbbx06d
 c2aeCwdi8WPHDm86cwzCIbRsaOrhjafHFuoVy0iqQxQXKJbzxhEq1YlZuasWpUTlXMPhAmfOe+U
 rq6ssSxFis7GK7YyieWff0vKNe8tzrflWoiulsvlRqnSu6yVNamr+/p2v/D2YtKMevZdn9++d/T
 blcZxHrbPjk6ec+7Hnv3jH9ed2v/69sOt7em163vf3jZ8xrpLLzn/04gjCcsIIeBCCgER7Es0RB
 QAABEtUDADJmE/yaRCqMm6HVoPfO97hw++jhDiwLLNzZ3dXSdOzHPmLS7MrD9t9cjYTEtLi23bQ
 RAYhpHNximDSsUFLDU1tx3a9y5gpEd0L3CRrGimwhF9563Di/NOw8VEaag6+8w/XzM1PeY59Opr
 rtl34P2HH3g3GkmFth1yxBj91peuWdWiEceRGnVPVRD1iSpHmAciXU73tTtFgrT53PKzF4rIm5v
 1Enr2lHUzI1OEelgGO2TA2Lq1qzVdj8Vba4drVTp62qnnvPLc9ovPumQgGZlA+YGBlp3v70dILS
 0t8oCmjCa7VHYq8zfccNX29972bMZDLuOoA7aajLq2F483+Q0/IhuCUCYHAQvAppIRETKBwP/e9
 740M3F448YtC0v1ZYODJ6cnTFVJJOKcC0zUbNJoVKs08COKxj1f0mOzc3OF6lLVLtq0evVV1/X0
 LpuYnIrFEo1yA1Gcny1eeM7mdFw+NHqC+lLEaDl0aPir//o5TcNHju7NZlpPHJ2plhqcUs2IEu6
 uXhZtjsQJFwEAYBGNmuD59r3fvOH1vxT37hw7dZ2UjfQe3vXO2X0DZ+dasoO9c43qulXLnWrVpU
 zX4oiLU9atLlQKoIo6tSJoTUdP+sGf/3FwxemBMaKbubdeeLuruZf6oEc0IcTC/HxHW7uh65zUP
 /+FW7LN0tfu+qePXbH+tdffkZDnu4IFtkSEYJxSpCjx0AcAjkHBgBn1Tjt1xeTo8cPHRmRF8X2n
 Wiopsuq6rud5jLFGyJyQpppbW7qXnZiaPe2UtdOTs82ZtpZs162f+OwTT/x2cnLC970wDIQQ9Ub
 tpo/fODp24hM3/+PWc8944fnXCeJOyP749LbTT1/d1zdoNcJXXtoXiURkLWI1agjEYHdq7RlNhA
 NoukZ9zgP3nnuu7enHV163/o03t29/e/GKKzfX/Or85HHPD6JDA7nBzhhGjZLV3Nrh+8H8Qr5UL
 uWacscnjg6fPGSi+EJxx853i6++fOjzd3/x0AfvzI5OXnvNpdmm2NxCsbW1dWF+fsO69auGhg4P
 HzMNEwEdHOjxvPK6tc233Xb1qWtyd9x+/Z13XN870JxrNSenjlMeAhWAMGXc0JXxk6M3XXf90tJ
 Sd0/HzOSkRGRZlvv6+hzH0XU9FyX10lJUl6fHT5iGXLfzX/vaF6dnRo8dO3h4eA/nTFVkwVmjXu
 vo7CwU8vV6LRIx33vv3ZmTR1avHOjt6Tw0PIqINnzoIHD9qSdfiEUT1YrFgOty2NMWPfOU5cmmz
 QQQCAHAg8/edmlPd5YCp5KzcdO5r/7txK5d29duXFO3SloiM9eodXe1nzg4jBlZuWZNrV6KJbNn
 bTyzsJQfGFwWTUQmTkx1tGa+e+/PHnro4b+++Nz3v/ONtubOVNp8+/13bZu2tLRghGkYuo7jecK
 y7MGBwW3b3rzowksE+JNT45dffsnU9MmZ2ZPTc9O6IV9/w7WptD52fMILqSQTzgULw1NW9Atgb7
 /9Rk93j2s56WzWsqypqSmEUFtT9sorrvrev/+43KhH43HNjOze/UGhsChLBBNeKtZaW1omxsebm
 5omp6d7e3tLpVIulxsZGcmkk6qutrY2D394BAti2XRyYsp1gFHBGBc8NGW49+u3ayI4PjWJsGxw
 5pqquO+eT/Z2tX/qjh+6XpNkcJ8XtbBDUWbiKbj3B3cXjo3kTKn3jPUmaA3utXQm3tlz9NGf/fw
 vf3waZF8o9Nf/+2JYwalM5Zobrvzt42/+5D//GtWgqQ3u/vaXsaCcc0WSO9vai/nC4tJ8LBazGk
 4qlUokktF41/HjRxEOPxw+sGnTmYFLjx4fXX3KacdPjBFKn3jmzZPjecRMzJlB7B987267UTx2+
 Hij6tz55S9NTEy88MILTU1N//enNzVDr3muE4SgKEkhc+pyygf7Mt3dLYMDvVNTU6ZpCiFkw0AI
 1ev1008/fdeuXUIQQG48EfVd+POf3qswKRo1CUGUcttyAYU/u+/TCRWcxYXv/uIVJMsEAMKQKYo
 UBBQQSEQiROacE4n5LiUyqCr8+Aefi8WU8fkZTVEHlg2tXNnt8XoukwLBypWGasR/fv9Dd99z97
 a3X/zpTx89fhCpMv7atz/JmHjkZ/+nG+GPfvxdXfcFDRlDUlwntLa6v3dkdELWs2HodbSkyouLa
 rJtLl966omn1p++KmF0vvXWG5GsSSCWTOT+499/a+oRRdPtRuFXD9znViuDff3PPv/io4+/kskk
 Z4uVSCTmeY6sgO9TTTUkGayGwzkA4GQireFGJhP53Kf+Yd/uD1rbOiYmJtrb26fmJvsGepemprE
 ke25AqVi+YujZ518/OrYYiWdrtYKpS7d/9h9J48TG00+3XP3O7zyIAECSpFgsJoSoVCqSJFGKAA
 AhLsn8yd/9m6o1XfsPX+EhDAws+8JXNtcr9d6ulV1d2UgyFtWl/fs+WLP2tCee+VNf19C/fPknu
 z74mx9Ia4euC4KGrMW9sPaLh2967OG9+/ad/OlPvxqLhPGkIssy587Q0Mp6vTE6Mt3V0UE9K5+f
 xao2t7RkRoxykZ8cm7/0ys1/ee59M8Z1XSsuiqf/8L4vhEyEoF4iYgaeZ3HWlOrM5wsYgaQ7mzZ
 tGFjeZpjq2NhYOtXkOmx8bGHnzmFZAsZRRE8ZirpmbcvWoYFjJ45XrPLGc7a++977HbmmjRs3Tk
 9ONaqNnp6ewPPf3bnv9feHkZFsNOoRlX73W18eGRn98/PvWj7HhBBKaa1W833fNE1KuaZqiqwoi
 iRJSFbqq9Z0vvraXxiHfKGcXyo0rPpfn//z3n3bQRDbdiORmO/7yWSSEBQx4b7v/Mfjjz3het7R
 k0+GvCZCuZh3Lrp4ay6n/OvX7u9ZtvzI0ePZZLK9rXMpXxKAY/FoKpGwbVvX9Yipn7pqVW9Xe09
 3VxiGL7/88i233OI49lJ+TtOR69mC+YFPzUh6qWxVHCqwOjc/HzIaT0bMCGpuiUXjcrE8E4ures
 RXdGfTluU/uf+rnT0xLCPLsUq1+lvv78u19wytWnvO1vOmpqay2eb2jo6ZmZkgCAb6eyOazH3n1
 KH+REzmnAKgVDr1i0d+/7snX2JYxRgTIZAkybpu2LYThlRVie+7gGjI6K3/dC3B9sRU+Z9u/apK
 DLtmnTi2sGfXyMxE8Z57/m0xX+jt6a5Vq5Gomc5m9u/fWSqE+/cduf32f3ny/5677vpz//rCKzS
 Q9+4YveCKvpb2pr07x+fmZnt6u9at7J2cnfe5cLxgZnKitTkuBPf8kDPx9rY3B/tWAvYdF8tyZH
 r+qON4S4vVdDrTN5jp7+yenZ6pNdxkNuu5bi6bbVg13cQBa3zz3jsFCvzAbpDLu5gAACAASURBV
 G/r1LWYAJZOp5aWFkPq5lqSW889s6c/NTZ+wrXhxdd2vLlj/8euvHD44P5TV605ePBAo1FPxaN2
 taIpcrlczqbjLbnM3v3HiKQiSZ5bqLa0dueXFkXok2uvXqEr4dJ8NWYmgsANBf/EHS2pLMpPR+7
 61kX/9vW//eWPr3/5zmsTbSPnbr5pz8F9//WTH7z44pu/+d3LN994OZJnFQNZNSOk9XPWX+SH+a
 6OTV/8wne6lotHfvFK4KEgCGOJ+AVb16uaPzs9dXy40juQk4ywXneiRtyqV1ed0lcs1lpb22emZ
 lRFbW/vaG/LSIoxOT05NDS4e++Hum52dXUVCkvpdCIU7t690xiI79gYcQIaIo4Z4bffeTmiTJVI
 LBqzHccwNdNMzMzM1+sN3/cxxiEE84vTHd2Z8fESkuKqab744rb7vn3X8PDBLZvPjsq6gmSEOMU
 srSem509iLYzpidmJuUroKcSo1KpA+K1nt+NiaSaRUs7YtKKtQzvn3KHP3HZTNR90tffKxF2agl
 J5MdMkVWrVRLxFVgTnMLR62d9eeRJhsWPHAc/n5XIZE2Royao1Z0RpZ3ci06T8/GeP+D4XHEfMS
 CFfO3JkwvfRVddebntOsVjPZtOaphmG0dbWXipWG43G/OJCT09PqVRqa2s7cOhDwzAqlYplWb7v
 y7KMMU4kEo7jhAGLx4miaBgrnONqvZBIaFdeeUkmk5EkSZIkxhiRJIwxpbRUKiGEACAIAkrp0ND
 Qqaeedss/XcZ4zbZLCMNDD/92yznn1ytFQ1NKxcVsOpPLtS4VFw1FljgqV6qIgCYZAQ+NqK4Cv/
 HGG9EFFydc15dAzWbisgJIILshpZv0Q8PD00f6AnXs3u9f+cG7i8/99QPdhLoF+/c9KhHtkku+S
 Kj89s5Hx6cOdrf3X3flZx57/KH+Fan/vP/nEkke/rD46qvvgADfh2TS9Bwhqc6Xvvrx+775lODw
 3//zcavh2rbLOSCErrv2ssOHD3e1tU9PTq1YsSKVjryz/QNdj5+cmKzYfjqdrlQqiURiYWGhqTm
 1a/uxN147DAIYg29+51Nh6JbKhXQmJqgghADBkXjMsixGIZlMnjx58qNUtFStdHd35/PFFctX1+
 olx0L/+8DzMlBVgt8+cM/85ETMVLlAoxOTEvIUKqamak/uOOYSFFebKs4SwvCJM3puvvZqdP6Fn
 QQjlcApQ32yhB1/pq9nq+XWKKHfufvFBx+5Za4w9dOfvIL96B+f/95ll31FJZDLKaMnA1kD6sP4
 +NuLSx+0pHuPHnPvuPMzd3/rhmp9SUZNRlTZt+/AmWds2rt331P/d6huuQ89evfSYvU/fvDIn//
 00+HD+2QFj46ODvSvMCNavV4PXM/QdFVV84W5RsPasvm8qampfN3VNK1er3POa7WabrJUsllwSZ
 ZMSmlI7Vgs5vtho2EnEgnKmKprNauxsLAQ1WMY43Xr1imK8uKLL/YvH1hYyA+tXP3ue2+0tzYxi
 g8fWNi9/UPPCVoy6n1339koLbjVYlO2tVgr7dx+8PDJ8pzHPEqjmH/8uq25uBG1a9m2DmyYMiaU
 SDwa0aKGvqzrtGMjJyNmxz13P+Ny58TogXpFiiVwzbIjkVjgg6DQ13N6c3P6C1+5BWO46KIbo1F
 zcvro4Cpjbt7bvGlz1DDbWnKlUiGbTRdLeU1Tzz1vQzKJfv2rx3VDicXxrbd+PRJNUx72D/Y1nN
 rk1IzteMl0NpXJ+n4YSySW9faPjIyoqhqNRiml0WjUMIx4PK6rzZ4rwpAxHhJCEEKFQoEQouuqY
 ZofXV+tVhMAnPNisXjgwIF33nknk8nMz89blmVZ1vIVA4Evbr755hWrWmwvUHV1tuS7IGuxBEIC
 aHhw/8jkUnXW8QXCGFAQwA3nb81IUm/f8vauTnTLP67NZBKYiI7WoYP7Rx976jUQctRUNS10a5q
 sIcuqfevez/7n/Y8+8OCvb7v9MyJQtEiAAH357it+9O1XFIXuGX7QkFu1ZG3uZPTJJx646xt3LM
 3Wd+7dpWlKX9/Ae+/ster2mjVrGo3G7bf/144dj2/ZdCvjoOrwX/d/s1LNq1KDEEJD7vthEIRcQ
 rIsq6oaBEHo+EFAjUjMdj0kESpoPB63LOujkF2TlXg8zjnv6OjYfeBIPp/PZDKFQiGbzQpOLasR
 jycQIqVibetFWyYnJ0dGRhhja1esPHDggKoYw4fGjx+bdV2sIH7zjRdTqzwzuziZp5OzCwKDwuH
 HP7zbLx6OyfFULK6jgCgKOXa0umfv1N794y+9vGfkRJ4yDqCGof/5L/7De+9/4AaUIL58VWz33s
 kXXnj58/9y9fTc4cf+8MO/vfTGyZEyD2O2U7/+prMO7D9w6qnnrFx+8VlnrTx67PCG9acdPXIyl
 8tsPvusRqO2cePprtv4cPjA2rVt8/PTn7/jimuvPf0zt13WlJEScRBE5wJTLjQjomiapioYoXKp
 HDEjgoexZCKgvqKpkkLqDadWq9u2gxCu1xsNz63bdrlWO3bihKaZ1Wq1o6PDtu1SqaQoCCMyOzt
 LiMR4GIbBZR/72PFjxwxdv+ziq1esGNiz/+3TN5xdzDcqVQ94ePDQyVLNOz6VL1ZsXdfaEurXP3
 NNc4QA8Gwqu7Qwj4AphBJNTzCOgjAgskRFGI0qgU9iEVPVG5kmPjNjA4IvfvkT+w4cpky+95777
 rjz1n17P3zz9X2Lc56shOkm/NnPfby9LTc0ePW/3n2rIqGrrrz6d7/71eduu7Onp+25vzzb2dE2
 OjZaqZQQEtls+vOfv+PIwe2tuSZd0WqVasSICSJhDIV8ESEky1KtUkYAsiSFQSAbKkJYUhXbcV3
 fi8TTtUaDCfBDGlDa0dNzwUUXK5p+zXXXj46MmKaxfMWg6zqarp5xxikb1m/s7l62fv1p1Vr+qq
 uu3Pb6a7lc054Pds9OzR07dmTVqlU/+uFjtYrr264k63okXijZkhpNxmS/bhdP7gmLs4XZiaViX
 VfkiGlIiqooGgmpgzAXnAvOBQhZpYGPgPNlvWnDJLOLFV2TOzs6srmuXTv3zc0sHh8Z+e+f/SYW
 TYEAy7NvvuXC09YNccZ+//irvYMJXVPeeONNAH9oaDXCDAAmJ6fjiXSjYZlmBGPy7LN/PmPdhhM
 nJsrlarappVZrSBI2NBUJ5rl24Hqu52uaJsuy67pMoLrlYEQcz8dIHhufME3T9/2BgQEAyGSyB/
 YfWL9u/f59+2vViu97c3OzS0uLV199VVtb5uWXX2vKti0uzg8u7929Y7fVaFx04YXdnV1joyd03
 ViYre/ZNUZDigWEjPshwxKhvt2RVf/wq/957Jf3H9x/wHODdLalu7tt566dp645TdLTKBk16g0H
 ABMkCyE+/tlTnnxsr4wjjFtXXLlWNpPP/OHNuJGqOGUAiEaRZYlrrr5y7fruzZvPkc35cmmxr2v
 17x//3WO/2XXdzf3gK416sHJlbsvmzT09XYVC6aUX3syXy21tbePj4xs3boxGo4JaJ0aPL18+EA
 RePBHTiey6LggkSYrv+04gz83NybLc3Nw8na9MTE5zLoKQ6WZ0dmkGIRSNRhljuVzObVjJZHJmZ
 sZ1XSKju+66ixDy6KOPnnXWWckU2bP7+PjY3PIVfStXdb/011eEEN3d3cViMZmSK0X+3z96GYHi
 +mWNgBqL1ap1CcMzjz+8blmis7d78sPhYo26IctPT3hBRdfVeDTz1CsHpbrjCqRIMmbcYxS/9dr
 eTZs7wkA6uIdv23a0XvczWe32O68bGd2/bFmPbiQ/ElqrVd558wVJs847f7Pg+Mf/8bfuHtyaGT
 h8dN/q1asxUYRMhKzKRmS2MJvOtC8WS7FEnPEg8OxD+/effuYZAlgylStWignVAJAQQp4f+n4oK
 xDQysr+dYfGTjYq1VOGeo8cG6najfMvu/Cvf1265pprnnvuuba2NkkipXoJq7hnoGdqaurCrVvG
 Ro9t3757bmZ+5NiJ6cnxbDZ7041XPvXUU53tLaqsAeL1Wq2lqeveu35uWQxjwpgDALKWcF0XIai
 M7ysfO5BfmDl2+ODg4OCJ0Q8mJyfHjo6fs3G1Fuu65ye/2je2KEnE9JkgmGDJA4HmZmHD6c3FvK
 0omudWb/nUOZVK5dDwDoQgHo/TIPI/P/8ZY5BISq1NTa5ffumF13747w8Ah1jcKJeLGzduHB8fu
 +3T/7zvwA4EUiQSiUQijUbDdd3mbNowjN07dqabskeOHpUI6u1dpiL5o1waY8wYA4BYLFapVBRF
 2bdvX1dna09Pd7a5ZXqhOHLkRFd7x67tO/7lC1/8/e9/r2naP3/mn59++un5mXnEEUKopaVlcXG
 +OZedmppav25dS0tLJpM577zzdu3aNb8wPTS0OhFrXpizLIuBAIwUWZebmrKLi/NxjT700E//8u
 TvmpNJVcP9fYM//MGPvvnNbw70L29uGY+FMwZm+8YWB1oAEQkYBVmFM87q9hxxaJfHyRIHOP2Mr
 nQT6mzpsCwnlWz59aMvMgY33nw2Ex4hqKU106hV2traKuXa6Rs2Hx4eWciPOI7T3NwciRiDg/1b
 tmx54IFfcA4IiEASAKwY7Pc9e98He/pXrBw5fnT1iuWxiOna9uCqwY/IRxiGQRDUqzXNUONaKtn
 ese2tbXNzC+lMc1NzRxjQc84/+80330ylUpdeeumf//znd9/ZkclkfN/XNO366z62c+fOyy+/8v
 ixE/F4cvXQqqNHjz777LNr1qxRVbVQKGCkf+/bD7JQNwytVKroaiQWUeqNSjxOrjnrlMH23Flnb
 X71/f3nb1pv2/aqVauy2SzWNKBC6t2kmUZOg6/9w8cQQqCpUddvLB/K0oCcPLE4tFaPJ4xUsjka
 U058ONLe3t7W1lEsFjOZjGRSIYT098LJeI4x8Ymbb3zjrRcHBpepcqyrq3dxcV7V8L9//8ednd3
 1mvXpT9/21DN/UlW1o61l+MMDgrKzz9y8Z9+ezu6OIPAUXUsnI4ZhEEI455RShUhe4Cb09O7DR0
 p1r16t3fute/70p6dOW7v2N4//7pJLLpmbm+vu7s7lco7jaJqm67qmaQcP7F23bp1juydOjNXrV
 r3amJ+fb29vtyyrpaXllw8+PXZiQcKGJCkODVRZ8SvVb3/15nM3ry/Oji7NlT9351f2b99RKs5T
 gbu7u33fP3DgwGWXXdZ/9g3UNFNR9fZLN2TTGQIgK1IEIeR69tJCva0Tcu2yqiGnIe3acXzFYEt
 HZ9v07Fg6Y1p2OQy4LKmCYxaiYrHGKLEs3/PsfHG2o6O1r3f5N77xzYsuuvDFF/9CQ2FZ9vp1G1
 5++RXdMCmltWqlVqskE4m1q9YMHx7uG+hbKhZXrlo5PzuNMVYUhRACACdHx5KpBA8h19lZa1AjY
 pimnl+a1w1pZnYxmUyecsopQ0NDlUolDL22ttYdO97P55f6+pal05lcruWNN94slYoiFBHTlIkU
 i0QrpfKzf9qJACuyWatXGQslmfzn9+8xUWOov70pqpx66lkfHjpu161Gab5muYosS4S0tLScf+l
 tZVlPY+db/3Lr0EC/QCGRFO4HDgji+0Fzi7J6VScP9JEj+VxzpqsrZcYM23Vk1fB8Xq05mVQ0lU
 ypiuw5thkzNJ0QiZ8cH5Mlo3dgoFb3GMOvbXujXK6fsmadH1DH89LZjK7IvudKEtE03YxGDx8/G
 k3Ej4+cSCSSYcAEg6ZsEnFbUkzAKhZMcCFrkoQYlpX5uclDhw784Nvff3/n+6qmbli/7pe/fPCS
 iy+anZ0OvCBiRmjIPdffvfPAK397dX5uDoBjJHwQuaamvTsOP/abP2/fOR66DJCqanJMRz+4+9P
 f+OKn1/V1lhYXM02ttsemJsd9p5rMGFyXJTVy4dU3nH3htU++vX/ashHjbU3xtWtWN8U1mWBEiM
 yYUFU5m0Prz1hul9mx40fWrl1dqsy2tGZqtQqlNNuU4oLGYjHgzDSjBMuqqkWS8SAIisViKpVij
 H3i5hvv/68Hcrncueee89bbr8iyJji54oortr3+ViJmDg8Pd3R0DA4OjoyMcMqy2Wy1Wl2+fPnM
 zMyy3u7F+el6pbRyzbpKrW4X8rlcTtf1Wq2WbO89PnJ0y5Yt+fzC66+/nspkU6nU7OxsqVTKZDK
 eIzLZlCRhy6r7bhCPxzXNWFhYyuVyv3/s1Z07jq1Y2T92coaBivxaJhH76xO/Wt2Tkwnyff+VV/
 7W0d11yqlrjg0P+42GKivVWpkR9MjTb+7YuadgMQoYJDkqyTih+oHbFYnLwQKSZTkMmSwTIyLiC
 cOu1defvqJhFdvam4IgUBSJEJlS3tPdizGZmS2fPDkR+LSpKRdPk/7+/lwuF4ZhIpHo6mx79933
 zj//PFUjugmyZAjB9+/f+867b+UyrTfccMPIyMjo6Kimad2dXSMjI7lcDgAsy1rW35NfXJoan4q
 n015AMQ2CIPgITnFJiUSNRqMRBC7GmAlIpVKmaWqaZlmW51kAOJttbtQtgtHCfP7Rh56tFEAwvb
 2jeWJqWtdlAsxU4I0XnpkaPdbf1jw5MdHb23Xww+GtF160Z/ee7raOsfGx/v7lJ8emLrn108loZ
 wNAUuVoMlVcLABgACoBSJLsCSaDhIgEACA4xhgwgZUrMh1dqVJ5sak5JTiRSbJWbXyw+5jnAqWg
 6oAQ4ZyHgaACAEBVwfeBEGhu0hsNNwhh7dplDz/6PyPHx2fnTs7MTtxw49XDh/auXbt23759jUa
 jtbW1VCjOzMysWrUqHo/v3Lkz2ZRSsVJcKgVIyKpi6KoQAiGUTCajkXi9UXVdN5WKK4qSL5Y+ev
 8oYZmanCZY97zQsekDP/tVowGBB5l0wrZCAJA11aqWUzE4/MGbx3a/39GS27NzR7Z1WW9f62Khq
 JqRtmSuOL9Y8+rlsnPeRR9rWb5JzyQChn0WBpypAru2HcHQxJUG+AUAijHCGAMAQugjrphrldec
 ujKeJExYh/aUpiddx3UiZsTzPAAgcuh7CgZMFIdRlM20LOXzhADjIRYIJEEkBAJxSoy42qg4IIg
 RSQeoSj3viad+ms1JVas4daJsGOrI6Ift7bliaSmd6MUYf/S7A4CsBpxzIYSqqiRUgtBzHCsIXU
 1TBIkBEIkY5WLDdd2HHnza9/2PWI2uxRhjtm1TSgkhaVW98cIN93/nq+++++6aMzblG3XLskqlE
 ue82cDrz9kyc3Lm6OjEQqF87tWfXDG0XtZkyxNmJGG5ZVkxJIFl7CPMv2MZ+6O1sgwPl82ndP//
 M+vvlgE/dX1L3/KU1fBefHYWE8o5xxjLsux5XiYba2qR/+0bX3/m6ed2vL+vXAoipmFZDgCoCib
 YpIwFoQMEFDAUg8sqwmqoo9jcXJkIIABxU/36j69cnLee+v1b87OepkQZdz7q/pFHjGkRI0IpZY
 yFrG5G1CAICMFBwGIxvdFwCZai0STBct3KhyElBAMADeEj/R/57gfe1z97xTUXbgGAbK41rZmma
 UqS5Pv+3pFJy3LuuudbiwVbM6SFGmaCKpocUB8TkjGlUtlPpLM+o1a9ririPA+GQN6ClZAH0kdC
 PyohhCpHg4AyxjgHAJ2xsizLAOB5jqIoxWL16/fcxlFZ1dDW88569k9vWbYDAJlMqkbLfr1hqs1
 BiCMxk3uuZdXBBmLKpUbVNKO27amKWrWdWKQ12huZn30ZhOT5CAFBCBFCMEKAIJnCnZ1NlFLf9y
 Pmas93LMsyDKNarS4tzmAsScSo12xKuawACMQZ/P+HzTlnjMUS5p9eeOORR14gAFdfe86nP36DZ
 Vnj4+MPPPDoggOKSuoWwwo4LteiSbtRSaRSteqiosLvf/2LL3z5q2PTBck0QSAfoRP/r40rDZas
 LM/P+33f2Xu/W9/bd5n9wgwzioACY+KucQHiFq2o0VRUXIgmmopUGdQIGOKWGERLg6WUxiBGI6g
 gcQMJyzDIIMsMd2ac9e5bL6f7rN+SHz1MGOSt/tNfd5065znv9rzfOQ9kAC083s4kCSGeenG9D5
 bv+PHO505Ua8GPfzDjuEwppbVWygD41LXvuXD3WVkmL331x2DQ//i+H0URYcugvTA91TvvgsaLX
 nHurbc8/tM7jymNDJTD5GCiUst7q8UBP2/hjW98/S9++bNer9frJbbNnu5ZeeYwOrXiBbkxJKVK
 E1WplFrtTv+muq7gnCexfPptBtB/CckYY4RrEak0JaAxNLaetZIk8TwvjuN+oORZBiAoFPKsx4z
 RGb7zrWu3bZ5kSbLzxS+571f3vPlt719eTSpwVwcMkgyREdz+f7CewktzRmPjlfNeMD46svlrX/
 0RgCDwieiqq67atD277579X7n+ZkGVNI1ty8+yPM0ix8WOsr76Q8/liwdq3lC4XrGHO4mmDDoDF
 vPxyvDk5Z/4Xi91BNlShIXATRNNxJMkEwKMsf6T3gAcT7XbOQDOcdt/3fLOv/jL9WbP4hwQiSLG
 YIzmnDMOKTMi6p92P+X12SURSS49l8ehgkGt5IdhZAyMQankNcO4WCrJLE3idGio+qUv/N1wpVw
 J3J2bp5JOSxmA66BczaT/mldfcv9iU7VhgLLxQ0+dylmnTWvNOVVrhVe+bnur90SRN5ixXNu7+K
 LnVWvFQ4vHt2++9LJL3hH4XtpjgnqJDShvp46v/uspMrrkWYLByJQXquvLa67r5lzpEnNy57FZ6
 8rvP25yN485WG9gWKSxZPCGSrHQuOnGzx88eGBkbPSyN1+TCFhULLndm778nuLgxFvedtVSC8Jt
 wCxIWE6aKi5ybZVNnMEh4aUyVsUUqeVmNIzsI8+reBWZGvsrv15fAppOHWlTgA17taW4pViPCBV
 RCdOSJZZnHv3OxPSWE3v2jtQ3KCosLx4WQriuOzg83Gm1dl782jirt7pJTi1XOM8CVv8p6C3T1T
 e/9RV77/7V6Ojo0aMzeZZxwkc+de2bLv04GXieG6mE5z7nQYWt3PChAcEcQcISLgyTUscqLzlOn
 qc5dIWzMPX/5utPLPqD0Upr91bny9dfu74+H/eSgj9wfOnYxHgtKPnX/NO3V9eTB55ctLn7jevf
 k7UXh8tBqpnlFv3q1tdeckVQLSvD260QABiDwUaW7tpYzeLw0NrAyWRp93b3A3Vf5OtxDhXDeKW
 T7eyumeRu7aRM8cESb8dZWnAsyymsdsIMCkUb7aUnwvXFNFo0Ohe82kegVCoR0dxqtzQw2pi6oD
 pYbaY9Ol2z+0ZkAEZEucxHR2uvfPmuYuCOjBRr1YJl8ys+emMWo1KuxHEsU0egEwDf+NiWCZev5
 6kxZJQBGCPBRJ7H0dpqs7Fpx76Hlu56fP4nx22/EGRh8zc/vqYXdZRMapWBJ594cvfFz59fOPqD
 O+761i2PNrssqJS/eNUVBT6zbWoqiqLxqfEnD84IO5iefs7hBfuSS98V8YKjuhXgU+exKalthsU
 MXI0c4c3ipN4+qw7bdriQTtT8rBUJC4rzK+bVUIR/vGzSO8t+ZGXlvj3h3sODbblMRnhOIFg8WL
 H23H2zZdo2H+4XNKUU51yUa9H6CeK21mOTz/njUznrtEmpiYwxxvddpcxwfWhldX7XzrOaa2HUS
 xaXVzhzpZRaS1dY5fpYvHL85Rsw1yPVMZ5AxUUxQGMIE+MjJxaXDh1Fh/DbE3Br5eVOd4ujPvOF
 D2zb2qhWBmaPzzqOQ9rMLi/NHJy9+p9vVX4hSuVHL9/9ij9KLn/7vZ++7t2Voj5n53Sn1Sz6xWN
 H53JL7Nq2o3HR5S8dxqs2+4NJJFDKUswudSZLcF14XrG5llDGnJKr0gwAs5gi/fAyjQZ00bZas7
 vGC5GuFT75P90nwmKuYw45MFxvttddk63Pz/BsSSlFRP2CoDXa7aaGGRoZ0qx8RgwCAJht2wDyP
 M/z/OTcKrMKD+7Zv7qSzs+HRvelYcA5h5cvzWeJmfzfGTy6bo532Gpmm2KxNDzW2Hr+coeC4elz
 X3ThgXlob3C5nRBT/379Vc/ZsaG1sjB79PDGsXrJsSzkrW7v4UcO2pYVRynj9JNbf7m6dt/tt//
 b5/7lxjTP52YXHnn0seXl1YnGZBwtnzjyO8vGORtHqyypBWC6Y7LOlgrMkM1sr7uaZ9rY62m41o
 7COIrixaUecVw0HI2N9Gbik1CRNe8lx7p/9qfjWoeFgu85Ynl5NZeM7OLExl1ra2tieLgvR5AkS
 TeMBmqNoaGxtdX55vIBcVoO4xRUzEhphBD92giVZFESuKUs7YISAErFjs0ARrngWDAaawweOS1H
 rUTZoaNKHgzpgXkhhG13jDmRc0FqdaiCO3/81d7ikW1bn5+De9yZ+f2xoFQsD43c9Mkb7314AaW
 6US2j1NF1fPUzgzfe8Mu///PJTROLP7sz9hud8siYSLvVxpaSspxSUOllo5F+qOYVUWRJl4o5X8
 isUnFlLaxUCmt21yd/cS0aGS2NjrAsbCUuRStmYNxtsuTsHVvKkfr5ncdRLnZlWk9l4LOWzjuZY
 tpsuOBNaaJaiw+rrO1b1lJzmWzmOM5AbSKNnyVnneI9xhittYYuFF0T5pe9cuf09Eip7AFMCMux
 PScoOI7jeZ6UMoqisQ2b4zgOgkBKGYbhD7//84HB4vYd0zvO2daZ3z8wWHUdNjQw4tjFJ2cOT0y
 WvELxwMz8dV+4+fa7j3FUBqsLSYo0EgmkVa6Wus2Gi7fswubtwwvd9S9/T37ia+87d5hbSs4Xzn
 /Nn1xxwYaz7j/2O1MIgm7vrUVc7HvNdmwYDFAu8zg27Vgzi3OhRgY8z7UF01EWigApx2QjmEt7c
 RF2hIaFx9KpAyviP/f+vlci6tgGiiBrBRzc/1BtePDgvjtGR4YcqoEZLoSgM+3pnZ5l23Gc2hCv
 ftnO6a2DYWvRFtoiNTJUcSwq+qJSdEqB5TtE2TqTnaKjbBOlQccz7AAACCpJREFU4dKu6S3nbBv
 dNjVI+drG8UbYaskcS4vtI0dmL7rwvOMnDhly7/jFA9+95R67MMbT3s2fe9WV73rZkQf2nOzZqZ
 KsrJptMeKywSQciUvzs8n39j60a/rCDSMULh2+5cGDh1fWuMNFj0fghYK1qR07vrMYqmLJaa7mm
 oxbLK63EzBwi2zXk6kWiQqYTz2VdzPu+SLz664XtpOxstXg+ZGjvbnCiMjbtcGBJFGCu5/97A3v
 eOMlo/VqkiZJNxWWoH7yf7pnne4h+gYSpWLtHa/fvG2Tb0NwLhzbK5Uqk+NjnU7nNAe2LM459zy
 PMdbpdISwsywBUC6X/XIhDMOwExljPM/bMFlttdi7P/iZmeMrS6Gqu+r7//reyfgh4XpzK+tiYu
 jlb39wnRUbo1uOL91/PmucPTT3xxsqjle4dy740dzM9Z9879hg4ZEjh265a27PXTMp6SkTf7pRm
 V9rhczOlK7YlkNxpK2eZIyTzJJB37aF3c71/k60G4h9eGe7JWUVbR13ksqUrlh83zH/w/s7INhu
 yRVW0l4bHmCSiXpp6LvfvnHzRjcN42eC1d87eKoySoKwfEvnNFFO//aDb2s1fz8wMMA5r9frnu0
 A2Lhx4+LiIgDX0svLy5OTk1prz/PGJiePHj0KYGpqat9v9wdB0Gg0kiQxxgwFQ1d++h++8tODsK
 rQ3v1Xb9xxztYDj+3buums1ZWWLRd7xrzri4/uPQ6oAIxbjtgUr7/vuYPe8tq8hZ8sm4fzAuyiS
 BOpwkGS7x8vVttJJ86XclR8bmUqLcBOwBNIQAEronyUZw+YNJaMay6hjJAglApjdnf+SxcUhvLu
 nV3x9RO11MqzXmuiQvvvu4Or9J69D77z3dcYy1Y+f/y27/I/zFmnU77WmgBhWzJTLM8nxqtVX0H
 LciEoBl4v7hSLPpG2bS4EWaxiW4XArxIcgmPZBYJjCZ/gDNcLfmD3onZtoOS4vJX0rvvsTc2ez1
 Vy0Xj7I6/b4OpOzcpMuMqT5nC1UQ/Km8e3zs0c7iR5zCS5VpKm3U40avxNqlBPVJOlJKIOj0agt
 wu8TMljPm8J07FABReOLrQMM0hsu2eJVcd6OO3NKrmmDDckrOCH/33D3gduVdFQJ+zFWtJ8WqvX
 b3uycyTVKgtLAfvdnrso7zq2ALG/et/l37zp2+ttaRn1LGHYn731uwcY4/hWlnJbJ5s3lc47u14
 oFKIoWlhYcB2eJAnnfG0tzHNEbYyNVfornPNu0imVirZtNxqNF71wOs/zsbGxiYmJVqt15ee/ee
 /9y8Ku+9ni4996g582CdqojBNL07S6obw2c8IKLGPR8eH3XviGD0uHkT/Co0SaVsU2FzKc20WgE
 HhuFEsJkwVqWVqGEeOWZ1CEiLJ8CfoJlS1pvUCAJyAhpCEiOAWTtJ74zbUvfcnHExttz/NXM5e5
 HV9kef6b267ftmliaGJk6dAB3/eLhdrBg494hUpj4ny/ce4zweoj1ae1WZb1Fby0EkKASOZ9nzM
 QNuexOgNlwHesKM0FwbatXprbAn3uNFqvrKy0GAMRjEGWD6VsRfoCKASd3qSdE+A6KHqwbG4rK9
 PeXDNktqWq9UMnTzquZ5JuyWVLUrkSNpxOwYVFlSgRWuQGbVIWj4nAGCgDMyCDnoJhABEXnkhzg
 lbQOQdgSBUaQfzIgevmZtXYpuru51++1EQ7EoGShw79umjrQtmWUUJccMOzLAKwON/euvstzwLW
 6RlAmqbaaAI4c5ntZmnLFzzNFAGeZ4eJBGPQmlkWEZlcaK0sy+6XBWMAEIhgNHfhum6v3RauK5M
 EQru55mKwJ8NykPYyWMKTWS64VBKZ5UHHQqPilnoqiRMJYmCAx2vddN3isJRI4RmklpdRDAMQrL
 ykTQYkxB2phK21Yoa4YUZbSiWkFQMAW7KctF9xemFac6wKy5933vTcrNx3+GTCjY/cL6BeZPvu+
 enc8lK9MZXKiOtqEkWOGy02/yDBn85ZRCSlfHongf7ASGkADMjFmd2sMs/8J8EwUlozOJZUlmBd
 k0CDafv0YY0xxPLTnV1/B9c8ZcpAMM5AAJTRihQZCIIAMYPcMGUMAMFYZilowzQUARwcgqQ2xoC
 R4kRSGQIYhITj2ZnMcg3LgZZQsJDnTNjaSHBT5uVu2Nq/7/ZtU068tiCKG1bXW5bF47DTGKlTn9
 w8/SL7tLsPFs40IiIDIhKM8X6MnTZ+JnNSWjEQkTQ65RbLpE1ITO6AgWmiUyFpDJwcfej6dcUQK
 TIS0ISqsjIoDSNhACJhaRjdh5XgKq5hNCEnE8AmA6aNhMk5GONcgxlogmLIcqlgDGCDn1JZhcmQ
 EmOOgM5OSXdqRomRrudApif2391uLvk8r1UHM5lnUifd3jOJdB+sfnea5/kzBjgAODEisoWwszO
 gVGe44CnPApE0OiRClnOCMapkxAug+sfvu8+AjdOeBUDJvuITaUJFWm2TpcYogsMZM1AwEkYRNO
 CDcQ1DiEhvygtEJEC50QnplDPXMBusD/Q+N5FSJpnODI4JwIBrcBeZRklDcygiBcpS7fte1IsBl
 AMrcOxb/+Pz1UAszM5NbtlmlBbPCLRn+NEfLp4eQGt2xq905tf+zPnUkjI4JTQJGNMlQzilKmoA
 LftzoVOeJQAYkDbMQKlUARIgA651ATBAv6wYAhntAwA8YJW6HOAMuUFqEEr4DAEnItKMdvY0AyS
 QEV5rCkapMshTTqryfchjosjonqaOTiPXi7ppqTbQWV/pdnO3Ohqun3zhi188O7tQqlb/D36qWu
 GG2VMFAAAAAElFTkSuQmCC
REV:2005-01-23T12:22:28Z
ROLE:VCard Test Engineer
TEL;TYPE=FAX;TYPE=HOME:home fax
TEL;TYPE=FAX;TYPE=WORK:work fax number
TEL;TYPE=WORK:work phone number
TEL;TYPE=CELL:mobile phone number
TEL;TYPE=HOME;TYPE=PREF:home phone number
TEL;TYPE=MSG:messenger number
TEL;TYPE=CAR;TYPE=ISDN;TYPE=VIDEO:Car ISDN video number
UID:jKbODaDMj0
URL:http://www.foobar.com
VERSION:3.0
X-KADDRESSBOOK-23/01/2005:2000-01-01
X-KADDRESSBOOK-X-Department:Department Foo
X-KADDRESSBOOK-X-Office:Office Foo
X-KADDRESSBOOK-X-Profession:Profession Foo
X-KADDRESSBOOK-X-SpousesName:Spouse Foo
X-KADDRESSBOOK-customnumericfield:123
X-KADDRESSBOOK-my_customdatetimefield:1999-12-30T23:58:59
X-KADDRESSBOOK-mycustombooleanfield:true
X-KADDRESSBOOK-mycustomdatefield:1998-12-30
X-KADDRESSBOOK-mycustomtextfield:This is my custom text field. It can conta
 in one line of text data only.
X-KADDRESSBOOK-mycustomtimefield:23:59:59
END:VCARD



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]