123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158openCore_kernel.Core_kernel_stableopen!Core_kernel.Int.Replace_polymorphic_comparemoduleStable_caseless_string=structmoduleU=Core_kernel.String.CaselessmoduleV1=structmoduleT=structtypet=String.V1.t[@@derivingsexp,bin_io]letcompare=U.comparelethash_fold_t=U.hash_fold_tendincludeTincludeComparator.V1.Make(T)endendmoduleStable=structmoduleV1=structmoduleT=structtypet=Email_address_parser_stable_v1.t={(* [prefix = None] means no brackets. *)prefix:String.V1.toption[@compare.ignore][@hash.ignore];local_part:String.V1.t;domain:Stable_caseless_string.V1.toption}[@@derivingfields,compare,hash]letcreate?prefix?domainlocal_part={prefix;local_part;domain}letwith_default_domainemail~default_domain={emailwithdomain=Core_kernel.Option.first_someemail.domaindefault_domain};;letof_string?default_domaininput_str=letopenCore_kernelinletopen!Int.Replace_polymorphic_compareinmatchAngstrom.parse_stringEmail_address_parser_stable_v1.email_onlyinput_strwith|Errorerror->Or_error.error_s[%message"Failed to parse email address"(error:string)(input_str:string)]|Okemail->Or_error.return(with_default_domainemail~default_domain);;letof_string_exn?default_domaininput_str=of_string?default_domaininput_str|>Core_kernel.Or_error.ok_exn;;letcompose~prefix~address_part=matchprefixwith|None->address_part|Someprefix->Core_kernel.sprintf"%s<%s>"prefixaddress_part;;letto_stringt=letaddress_part=matcht.domainwith|None->t.local_part|Somedomain->Core_kernel.sprintf"%s@%s"t.local_partdomainincompose~prefix:t.prefix~address_part;;includeSexpable.Of_stringable.V1(structtypenonrect=tletto_string=to_stringletof_strings=of_string_exnsend)includeBinable.Of_stringable.V1(structtypenonrect=tletto_string=to_stringletof_strings=of_string_exnsend)endmoduleWith_comparator=structincludeTincludeComparator.V1.Make(T)endincludeWith_comparatorincludeComparable.V1.Make(With_comparator)endendopenCore_kernelopen!Int.Replace_polymorphic_comparemoduleDomain=structincludeString.Caselessletto_string=Fn.idletof_string=Fn.idendmoduleT=Stable.V1.With_comparatorincludeTletlist_of_string?default_domaininput_str=matchAngstrom.parse_stringEmail_address_parser_stable_v1.email_list_onlyinput_strwith|Errorerror->Or_error.error_s[%message"Failed to parse email address(es)"(error:string)(input_str:string)]|Okemails->Or_error.return(List.map~f:(with_default_domain~default_domain)emails);;letlist_of_string_exn?default_domaininput_str=list_of_string?default_domaininput_str|>Core_kernel.Or_error.ok_exn;;letlist_to_header_valuets=String.concat~sep:",\n\t"(List.mapts~f:to_string)letaddress_part?(brackets=false)?(lowercase_domain=false)t=letprefix=ifbracketsthenSome""elseNoneinletdomain=ifnotlowercase_domainthent.domainelseOption.mapt.domain~f:String.lowercasein{twithprefix;domain};;letaddress_part_string?brackets?lowercase_domaint=to_string(address_part?brackets?lowercase_domaint);;letset_address_parttaddress_part=of_string(compose~prefix:t.prefix~address_part)letset_local_parttlocal_part={twithlocal_part}letset_domaintdomain={twithdomain}letset_prefixtprefix={twithprefix}includeComparable.Make_plain_using_comparator(T)includeHashable.Make_plain(T)moduleCaseless=structmoduleT=structtypenonrect=t={prefix:String.Stable.V1.toption[@compare.ignore][@hash.ignore];local_part:Stable_caseless_string.V1.t;domain:Stable_caseless_string.V1.toption}[@@derivingcompare,hash,sexp]endincludeTincludeHashable.Make_plain(T)includeComparable.Make_plain(T)end