vcard-list = vcard *vcard

vcard = "BEGIN:VCARD" [CR] LF
		"VERSION:4.0" [CR] LF
		1*property
		"END:VCARD" *([CR] LF)
property = (SOURCE / KIND / XML
			/ FN / N / NICKNAME / PHOTO / BDAY / ANNIVERSARY / GENDER
			/ ADR
			/ TEL / EMAIL / IMPP / LANG
			/ TZ / GEO
			/ TITLE / ROLE / LOGO / ORG / MEMBER / RELATED
			/ CATEGORIES / NOTE / PRODID / REV / SOUND / UID / CLIENTPIDMAP / URL
			/ KEY
			/ FBURL / CALADRURI / CALURI
			/ BIRTHPLACE / DEATHPLACE / DEATHDATE
			/ X-PROPERTY) [CR] LF

X-PROPERTY = [group "."] X-PROPERTY-name *(";" X-PROPERTY-param) ":" X-PROPERTY-value
X-PROPERTY-name = x-name
X-PROPERTY-param = any-param
X-PROPERTY-value = text
		/ text-list
		/ date-list
		/ time-list
		/ date-time-list
		/ date-and-or-time-list
		/ timestamp-list
		/ boolean
		/ integer-list
		/ float-list
		/ URI
		/ utc-offset
		/ Language-Tag

SOURCE = [group "."] "SOURCE" *(";" SOURCE-param) ":" SOURCE-value
SOURCE-param = VALUE-param / PID-param / PREF-param / ALTID-param / MEDIATYPE-param / any-param
SOURCE-value = URI

KIND = [group "."] "KIND" *(";" KIND-param) ":" KIND-value
KIND-param = VALUE-param / any-param
KIND-value = "individual" / "group" / "org" / "location" / iana-token / x-name

XML = [group "."] "XML" *(";" XML-param) ":" XML-value
XML-param = VALUE-param / any-param
XML-value = text

FN = [group "."] "FN" *(";" FN-param) ":" FN-value
FN-param = VALUE-param / TYPE-param / LANGUAGE-param / ALTID-param / PID-param / PREF-param / any-param
FN-value = text

N = [group "."] "N" *(";" N-param) ":" N-value
N-param = VALUE-param / SORT-AS-param / LANGUAGE-param / ALTID-param / any-param
N-value    = N-fn ";" N-gn ";" N-an ";" N-prefixes ";" N-suffixes
N-fn       = component *("," component)
N-gn       = component *("," component)
N-an       = component *("," component)
N-prefixes = component *("," component)
N-suffixes = component *("," component)

NICKNAME = [group "."] "NICKNAME" *(";" NICKNAME-param) ":" NICKNAME-value
NICKNAME-param = VALUE-param / TYPE-param / LANGUAGE-param / ALTID-param / PID-param / PREF-param / any-param
NICKNAME-value = text-list

BDAY = [group "."] "BDAY" *(";" BDAY-param) ":" BDAY-value
BDAY-param = VALUE-param / LANGUAGE-param / ALTID-param / CALSCALE-param / any-param
BDAY-value = date-and-or-time / text

ANNIVERSARY = [group "."] "ANNIVERSARY" *(";" ANNIVERSARY-param) ":" ANNIVERSARY-value
ANNIVERSARY-param = VALUE-param / ALTID-param / CALSCALE-param / any-param
ANNIVERSARY-value = date-and-or-time / text

GENDER = [group "."] "GENDER" *(";" GENDER-param) ":" GENDER-value
GENDER-param = VALUE-param / any-param
GENDER-value = [sex] [";" text]
sex = "M" / "F" / "O" / "N" / "U"

PHOTO = [group "."] "PHOTO" *(";" PHOTO-param) ":" PHOTO-value
PHOTO-param = VALUE-param / ALTID-param / TYPE-param / MEDIATYPE-param / PREF-param / PID-param / any-param
PHOTO-value = URI

ADR = [group "."] "ADR" *(";" ADR-param) ":" ADR-value
ADR-param = VALUE-param / LABEL-param / LANGUAGE-param / GEO-PARAM-param / TZ-PARAM-param / ALTID-param
			/ PID-param / PREF-param / TYPE-param / any-param
ADR-value = ADR-pobox  ";" ADR-ext      ";"
			ADR-street ";" ADR-locality ";"
			ADR-region ";" ADR-code     ";"
			ADR-country
ADR-pobox    = component *("," component)
ADR-ext      = component *("," component)
ADR-street   = component *("," component)
ADR-locality = component *("," component)
ADR-region   = component *("," component)
ADR-code     = component *("," component)
ADR-country  = component *("," component)

TEL = [group "."] "TEL" *(";" TEL-param) ":" TEL-value
TEL-param = VALUE-param / TYPE-param / PID-param / PREF-param / ALTID-param / any-param
TEL-value = URI / text

EMAIL = [group "."] "EMAIL" *(";" EMAIL-param) ":" EMAIL-value
EMAIL-param = VALUE-param / PID-param / PREF-param / TYPE-param / ALTID-param / any-param
EMAIL-value = text

IMPP = [group "."] "IMPP" *(";" IMPP-param) ":" IMPP-value
IMPP-param = VALUE-param / PID-param / PREF-param / TYPE-param / MEDIATYPE-param / ALTID-param / any-param
IMPP-value = URI

LANG = [group "."] "LANG" *(";" LANG-param) ":" LANG-value
LANG-param = VALUE-param / PID-param / PREF-param / ALTID-param / TYPE-param / any-param
LANG-value = Language-Tag

TZ = [group "."] "TZ" *(";" TZ-param) ":" TZ-value
TZ-param = VALUE-param / ALTID-param / PID-param / PREF-param / TYPE-param / MEDIATYPE-param / any-param
TZ-value = text / URI / utc-offset

GEO = [group "."] "GEO" *(";" GEO-param) ":" GEO-value
GEO-param = VALUE-param / PID-param / PREF-param / TYPE-param / MEDIATYPE-param / ALTID-param / any-param
GEO-value = text / URI

TITLE = [group "."] "TITLE" *(";" TITLE-param) ":" TITLE-value
TITLE-param = VALUE-param / LANGUAGE-param / PID-param / PREF-param
			/ ALTID-param / TYPE-param / any-param
TITLE-value = text

ROLE = [group "."] "ROLE" *(";" ROLE-param) ":" ROLE-value
ROLE-param = VALUE-param / LANGUAGE-param / PID-param / PREF-param
			/ TYPE-param / ALTID-param / any-param
ROLE-value = text

LOGO = [group "."] "LOGO" *(";" LOGO-param) ":" LOGO-value
LOGO-param = VALUE-param / LANGUAGE-param / PID-param / PREF-param
			/ TYPE-param / MEDIATYPE-param / ALTID-param / any-param
LOGO-value = URI

ORG = [group "."] "ORG" *(";" ORG-param) ":" ORG-value
ORG-param = VALUE-param / SORT-AS-param / LANGUAGE-param / PID-param
			/ PREF-param / ALTID-param / TYPE-param / any-param
ORG-value = component *(";" component)

MEMBER = [group "."] "MEMBER" *(";" MEMBER-param) ":" MEMBER-value
MEMBER-param = VALUE-param / PID-param / PREF-param / ALTID-param
			/ MEDIATYPE-param / any-param
MEMBER-value = URI

RELATED = [group "."] "RELATED" *(";" RELATED-param) ":" RELATED-value
RELATED-param = VALUE-param / PID-param / PREF-param / ALTID-param / TYPE-param / any-param
RELATED-value = URI / text

CATEGORIES = [group "."] "CATEGORIES" *(";" CATEGORIES-param) ":" CATEGORIES-value
CATEGORIES-param = VALUE-param / PID-param / PREF-param / TYPE-param / ALTID-param / any-param
CATEGORIES-value = text-list

NOTE = [group "."] "NOTE" *(";" NOTE-param) ":" NOTE-value
NOTE-param = VALUE-param / LANGUAGE-param / PID-param / PREF-param / TYPE-param / ALTID-param / any-param
NOTE-value = text

PRODID = [group "."] "PRODID" *(";" PRODID-param) ":" PRODID-value
PRODID-param = VALUE-param / any-param
PRODID-value = text

REV = [group "."] "REV" *(";" REV-param) ":" REV-value
REV-param = VALUE-param / any-param
REV-value = timestamp

SOUND = [group "."] "SOUND" *(";" SOUND-param) ":" SOUND-value
SOUND-param = VALUE-param / LANGUAGE-param / PID-param / PREF-param
			/ TYPE-param / MEDIATYPE-param / ALTID-param / any-param
SOUND-value = URI

UID = [group "."] "UID" *(";" UID-param) ":" UID-value
UID-param = VALUE-param / any-param
UID-value = URI / text

CLIENTPIDMAP = [group "."] "CLIENTPIDMAP" *(";" CLIENTPIDMAP-param) ":" CLIENTPIDMAP-value
CLIENTPIDMAP-param = any-param
CLIENTPIDMAP-value = 1*DIGIT ";" URI

URL = [group "."] "URL" *(";" URL-param) ":" URL-value
URL-param = VALUE-param / PID-param / PREF-param / TYPE-param
			/ MEDIATYPE-param / ALTID-param / any-param
URL-value = URI

KEY = [group "."] "KEY" *(";" KEY-param) ":" KEY-value
KEY-param = VALUE-param / ALTID-param / PID-param / PREF-param / TYPE-param / any-param
KEY-value = URI / text

FBURL = [group "."] "FBURL" *(";" FBURL-param) ":" FBURL-value
FBURL-param = VALUE-param / PID-param / PREF-param / TYPE-param
			/ MEDIATYPE-param / ALTID-param / any-param
FBURL-value = URI

CALADRURI = [group "."] "CALADRURI" *(";" CALADRURI-param) ":" CALADRURI-value
CALADRURI-param = VALUE-param / PID-param / PREF-param / TYPE-param
				/ MEDIATYPE-param / ALTID-param / any-param
CALADRURI-value = URI

CALURI = [group "."] "CALURI" *(";" CALURI-param) ":" CALURI-value
CALURI-param = VALUE-param / PID-param / PREF-param / TYPE-param
			/ MEDIATYPE-param / ALTID-param / any-param
CALURI-value = URI

BIRTHPLACE = [group "."] "BIRTHPLACE" *(";" BIRTHPLACE-param) ":" BIRTHPLACE-value
BIRTHPLACE-param = VALUE-param / ALTID-param / LANGUAGE-param / any-param
BIRTHPLACE-value = text / URI

DEATHPLACE = [group "."] "DEATHPLACE" *(";" DEATHPLACE-param) ":" DEATHPLACE-value
DEATHPLACE-param = VALUE-param / ALTID-param / LANGUAGE-param / any-param
DEATHPLACE-value = text / URI

DEATHDATE = [group "."] "DEATHDATE" *(";" DEATHDATE-param) ":" DEATHDATE-value
DEATHDATE-param = VALUE-param / ALTID-param / LANGUAGE-param / any-param
DEATHDATE-value = date-and-or-time / text

group = 1*(ALPHA / DIGIT / "-")

LANGUAGE-param = "LANGUAGE=" LANGUAGE-param-value
LANGUAGE-param-value = Language-Tag

VALUE-param = "VALUE=" VALUE-param-value
VALUE-param-value = "text"
					/ "uri"
					/ "date"
					/ "time"
					/ "date-time"
					/ "date-and-or-time"
					/ "timestamp"
					/ "boolean"
					/ "integer"
					/ "float"
					/ "utc-offset"
					/ "language-tag"
					/ x-name

PREF-param = "PREF=" PREF-param-value
PREF-param-value = (1*2DIGIT / "100")

ALTID-param = "ALTID=" ALTID-param-value
ALTID-param-value = param-value

PID-param = "PID=" PID-param-value *("," PID-param-value)
PID-param-value = 1*DIGIT ["." 1*DIGIT]

TYPE-param = "TYPE=" TYPE-param-value *("," TYPE-param-value)
TYPE-param-value = "work" / "home" / type-param-tel / type-param-related / iana-token / x-name

MEDIATYPE-param = "MEDIATYPE=" MEDIATYPE-param-value
MEDIATYPE-param-value = type-name "/" subtype-name *( ";" any-param )

CALSCALE-param = "CALSCALE=" CALSCALE-param-value
CALSCALE-param-value = "gregorian" / iana-token / x-name

SORT-AS-param = "SORT-AS=" SORT-AS-param-value
SORT-AS-param-value = param-value *("," param-value)

GEO-PARAM-param = "GEO=" GEO-PARAM-param
GEO-PARAM-param-value = DQUOTE URI DQUOTE

TZ-PARAM-param = "TZ=" TZ-PARAM-param-value
TZ-PARAM-param-value = (param-value / DQUOTE URI DQUOTE)

LABEL-param = "LABEL=" LABEL-param-value
LABEL-param-value = param-value

any-param  = param-name "=" param-value
param-name = (iana-token / x-name)
param-value = param-value-component *("," param-value-component)
param-value-component = *SAFE-CHAR /  (DQUOTE *QSAFE-CHAR DQUOTE)

iana-token = 1*(ALPHA / DIGIT / "-")
x-name = "x-" 1*(ALPHA / DIGIT / "-")

COMPONENT-CHAR = "\\" / "\," / "\;" / "\n" / WSP / NON-ASCII / %x21-2B / %x2D-3A / %x3C-5B / %x5D-7E
component = *COMPONENT-CHAR
list-component = component *("," component)

text-list = text *("," text)
text = *TEXT-CHAR
TEXT-CHAR = "\\" / "\," / "\n" / WSP / NON-ASCII / %x21-2B / %x2D-5B / %x5D-7E
NON-ASCII = UTF8-2 / UTF8-3 / UTF8-4
QSAFE-CHAR = WSP / "!" / %x23-7E / NON-ASCII
SAFE-CHAR = WSP / "!" / %x23-2B / %x2D-39 / %x3C-7E / NON-ASCII
VALUE-CHAR = WSP / VCHAR / NON-ASCII
UTF8-1      = %x00-7F
UTF8-2      = %xC2-DF UTF8-tail
UTF8-3      = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) / %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )
UTF8-4      = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) / %xF4 %x80-8F 2( UTF8-tail )
UTF8-tail   = %x80-BF

date-list             = date             *("," date)
time-list             = time             *("," time)
date-time-list        = date-time        *("," date-time)
date-and-or-time-list = date-and-or-time *("," date-and-or-time)
timestamp-list        = timestamp        *("," timestamp)
integer-list          = integer          *("," integer)
float-list            = float            *("," float)

boolean = "TRUE" / "FALSE"
integer = [sign] 1*DIGIT
float   = [sign] 1*DIGIT ["." 1*DIGIT]

sign = "+" / "-"

year   = 4DIGIT  ; 0000-9999
month  = 2DIGIT  ; 01-12
day    = 2DIGIT  ; 01-28/29/30/31 depending on month and leap year
hour   = 2DIGIT  ; 00-23
minute = 2DIGIT  ; 00-59
second = 2DIGIT  ; 00-58/59/60 depending on leap second
zone   = utc-designator / utc-offset
utc-designator = %x5A  ; uppercase "Z"

date          = year    [month  day]
			  / year "-" month
			  / "--"     month [day]
			  / "--"      "-"   day
date-noreduc  = year     month  day
			  / "--"     month  day
			  / "--"      "-"   day
date-complete = year     month  day

time          = hour [minute [second]] [zone]
			  /  "-"  minute [second]
			  /  "-"   "-"    second
time-notrunc  = hour [minute [second]] [zone]
time-complete = hour  minute  second   [zone]
time-designator = %x54  ; uppercase "T"
date-time = date-noreduc  time-designator time-notrunc
timestamp = date-complete time-designator time-complete

date-and-or-time = date-time / date / time-designator time

utc-offset = sign hour [minute]

type-param-related = related-type-value *("," related-type-value)
related-type-value = "contact" / "acquaintance" / "friend" / "met"
					/ "co-worker" / "colleague" / "co-resident"
					/ "neighbor" / "child" / "parent"
					/ "sibling" / "spouse" / "kin" / "muse"
					/ "crush" / "date" / "sweetheart" / "me"
					/ "agent" / "emergency"
type-param-tel = "text" / "voice" / "fax" / "cell" / "video"
				/ "pager" / "textphone" / iana-token / x-name

type-name = reg-name
subtype-name = reg-name

URI           = scheme ":" hier-part [ "?" query ] [ "#" fragment ]

hier-part     = "//" authority path-abempty
				/ path-absolute
				/ path-rootless
				/ path-empty

URI-reference = URI / relative-ref

absolute-URI  = scheme ":" hier-part [ "?" query ]

relative-ref  = relative-part [ "?" query ] [ "#" fragment ]

relative-part = "//" authority path-abempty
				/ path-absolute
				/ path-noscheme
				/ path-empty

scheme        = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )

authority     = [ userinfo "@" ] host [ ":" port ]
userinfo      = *( unreserved / pct-encoded / sub-delims / ":" )
host          = IP-literal / IPv4address / reg-name
port          = *DIGIT

IP-literal    = "[" ( IPv6address / IPvFuture  ) "]"

IPvFuture     = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )

IPv6address   =                            6( h16 ":" ) ls32
				/                       "::" 5( h16 ":" ) ls32
				/ [               h16 ] "::" 4( h16 ":" ) ls32
				/ [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
				/ [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
				/ [ *3( h16 ":" ) h16 ] "::"    h16 ":"   ls32
				/ [ *4( h16 ":" ) h16 ] "::"              ls32
				/ [ *5( h16 ":" ) h16 ] "::"              h16
				/ [ *6( h16 ":" ) h16 ] "::"

h16           = 1*4HEXDIG
ls32          = ( h16 ":" h16 ) / IPv4address
IPv4address   = dec-octet "." dec-octet "." dec-octet "." dec-octet
dec-octet     = DIGIT                 ; 0-9
				/ %x31-39 DIGIT         ; 10-99
				/ "1" 2DIGIT            ; 100-199
				/ "2" %x30-34 DIGIT     ; 200-249
				/ "25" %x30-35          ; 250-255

reg-name      = *( unreserved / pct-encoded / sub-delims )

path          = path-abempty    ; begins with "/" or is empty
				/ path-absolute   ; begins with "/" but not "//"
				/ path-noscheme   ; begins with a non-colon segment
				/ path-rootless   ; begins with a segment
				/ path-empty      ; zero characters

path-abempty  = *( "/" segment )
path-absolute = "/" [ segment-nz *( "/" segment ) ]
path-noscheme = segment-nz-nc *( "/" segment )
path-rootless = segment-nz *( "/" segment )
path-empty    = [pchar]

segment       = *pchar
segment-nz    = 1*( pchar / "[" / "]" )
				; to be compatible with IPv6 SIP URIs
segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
				; non-zero-length segment without any colon ":"

pchar         = unreserved / pct-encoded / sub-delims / ":" / "@" / "\,"

query         = *( pchar / "/" / "?" )

fragment      = *( pchar / "/" / "?" )

pct-encoded   = "%" HEXDIG HEXDIG

unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
reserved      = gen-delims / sub-delims
gen-delims    = ":" / "/" / "?" / "#" / "[" / "]" / "@"
sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
				/ "*" / "+" / "," / ";" / "="

Language-Tag  = langtag             ; normal language tags
			 / privateuse            ; private use tag
			 / grandfathered         ; grandfathered tags

langtag       = language
				["-" script]
				["-" region]
				*("-" variant)
				*("-" extension)
				["-" privateuse]

language      = 2*3ALPHA              ; shortest ISO 639 code
				["-" extlang]         ; sometimes followed by extended language subtags
				/ 4ALPHA              ; or reserved for future use
				/ 5*8ALPHA            ; or registered language subtag

extlang       = 3ALPHA                ; selected ISO 639 codes
				*2("-" 3ALPHA)        ; permanently reserved

script        = 4ALPHA                ; ISO 15924 code

region        = 2ALPHA                ; ISO 3166-1 code
				/ 3DIGIT              ; UN M.49 code

variant       = 5*8alphanum         ; registered variants
				/ (DIGIT 3alphanum)

extension     = singleton 1*("-" (2*8alphanum))

singleton     = DIGIT                 ; 0 - 9
				/ %x41-57             ; A - W
				/ %x59-5A             ; Y - Z
				/ %x61-77             ; a - w
				/ %x79-7A             ; y - z

privateuse    = "x" 1*("-" (1*8alphanum))

grandfathered = irregular             ; non-redundant tags registered
				/ regular             ; during the RFC 3066 era

irregular     = "en-GB-oed"           ; irregular tags do not match
				/ "i-ami"             ; the 'langtag' production and
				/ "i-bnn"             ; would not otherwise be
				/ "i-default"         ; considered 'well-formed'
				/ "i-enochian"        ; These tags are all valid,
				/ "i-hak"             ; but most are deprecated
				/ "i-klingon"         ; in favor of more modern
				/ "i-lux"             ; subtags or subtag
				/ "i-mingo"           ; combination
				/ "i-navajo"
				/ "i-pwn"
				/ "i-tao"
				/ "i-tay"
				/ "i-tsu"
				/ "sgn-BE-FR"
				/ "sgn-BE-NL"
				/ "sgn-CH-DE"

regular       = "art-lojban"          ; these tags match the 'langtag'
				/ "cel-gaulish"       ; production, but their subtags
				/ "no-bok"            ; are not extended language
				/ "no-nyn"            ; or variant subtags: their meaning
				/ "zh-guoyu"          ; is defined by their registration
				/ "zh-hakka"          ; and all of these are deprecated
				/ "zh-min"            ; in favor of a more modern
				/ "zh-min-nan"        ; subtag or sequence of subtags
				/ "zh-xiang"

alphanum      = (ALPHA / DIGIT)       ; letters and numbers
