docs: def make_vcard_data(name, displayname, email=None, phone=None, fax=None,
                      videophone=None, memo=None, nickname=None, birthday=None,
                      url=None, pobox=None, street=None, city=None, region=None,
                      zipcode=None, country=None, org=None, lat=None, lng=None,
                      source=None, rev=None, title=None, photo_uri=None):
      """\
      Creates a string encoding the contact information as vCard 3.0.
  
      Only a subset of available vCard properties is supported.
  
      :param str name: The name. If it contains a semicolon, , the first part
              is treated as lastname and the second part is treated as forename.
      :param str displayname: Common name.
      :param str|iterable email: E-mail address. Multiple values are allowed.
      :param str|iterable phone: Phone number. Multiple values are allowed.
      :param str|iterable fax: Fax number. Multiple values are allowed.
      :param str|iterable videophone: Phone number for video calls.
              Multiple values are allowed.
      :param str memo: A notice for the contact.
      :param str nickname: Nickname.
      :param str|date birthday: Birthday. If a string is provided,
              it should encode the date as YYYY-MM-DD value.
      :param str|iterable url: Homepage. Multiple values are allowed.
      :param str|None pobox: P.O. box (address information).
      :param str|None street: Street address.
      :param str|None city: City (address information).
      :param str|None region: Region (address information).
      :param str|None zipcode: Zip code (address information).
      :param str|None country: Country (address information).
      :param str org: Company / organization name.
      :param float lat: Latitude.
      :param float lng: Longitude.
      :param str source: URL where to obtain the vCard.
      :param str|date rev: Revision of the vCard / last modification date.
      :param str|iterable|None title: Job Title. Multiple values are allowed.
      :param str|iterable|None photo_uri: Photo URI. Multiple values are allowed.
      :rtype: str
      """
      def make_multifield(name, val):
          if val is None:
              return ()
          if isinstance(val, str_type):
              val = (val,)
          return ['{0}:{1}'.format(name, escape(i)) for i in val]
  
      escape = _escape_vcard
      data = ['BEGIN:VCARD', 'VERSION:3.0',
              'N:{0}'.format(name),
              'FN:{0}'.format(escape(displayname))]
      if org:
          data.append('ORG:{0}'.format(escape(org)))
      data.extend(make_multifield('EMAIL', email))
      data.extend(make_multifield('TEL', phone))
      data.extend(make_multifield('TEL;TYPE=FAX', fax))
      data.extend(make_multifield('TEL;TYPE=VIDEO', videophone))
      data.extend(make_multifield('URL', url))
      data.extend(make_multifield('TITLE', title))
      data.extend(make_multifield('PHOTO;VALUE=uri', photo_uri))
      if nickname:
          data.append('NICKNAME:{0}'.format(escape(nickname)))
      adr_properties = (pobox, street, city, region, zipcode, country)
      if any(adr_properties):
          adr_data = [escape(i or '') for i in adr_properties]
          data.append('ADR:{0};;{1};{2};{3};{4};{5}'.format(*adr_data))
      if birthday:
          try:
              birthday = birthday.strftime('%Y-%m-%d')
          except AttributeError:
              pass
          if not _looks_like_datetime(birthday):
              raise ValueError('"birthday" does not seem to be a valid date or date/time representation')
          data.append('BDAY:{0};'.format(birthday))
      if lat or lng and (not(all((lat, lng)))):
          raise ValueError('Incomplete geo information, please specify latitude and longitude.')
      if lat and lng:
          data.append('GEO:{0};{1}'.format(lat, lng))
      if source:
          data.append('SOURCE:{0}'.format(escape(url)))
      if memo:
          data.append('NOTE:{0}'.format(escape(memo)))
      if rev:
          if not _looks_like_datetime(rev):
              raise ValueError('"rev" does not seem to be a valid date or date/time representation')
          data.append('REV:{0}'.format(rev))
      data.append('END:VCARD')
      data.append('')
      return '\r\n'.join(data)