diff --git a/Makefile b/Makefile index 042f356e..7f099b05 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ help: # $(ZIG) commands # ------------ -.PHONY: build build-dev run run-release shell test bench download-zig wpt unittest +.PHONY: build build-dev run run-release shell test bench download-zig wpt unittest data zig_version = $(shell grep 'recommended_zig_version = "' "vendor/zig-js-runtime/build.zig" | cut -d'"' -f2) @@ -199,6 +199,9 @@ install-zig-js-runtime: @cd vendor/zig-js-runtime && \ make install +data: + cd src/data && go run public_suffix_list_gen.go > public_suffix_list.zig + .PHONY: _build_mimalloc MIMALLOC := $(BC)vendor/mimalloc/out/$(OS)-$(ARCH) diff --git a/src/data/public_suffix_list.zig b/src/data/public_suffix_list.zig new file mode 100644 index 00000000..76107c9e --- /dev/null +++ b/src/data/public_suffix_list.zig @@ -0,0 +1,9742 @@ +const std = @import("std"); + +pub fn lookup(value: []const u8) bool { + return public_suffix_list.has(value); +} + +const public_suffix_list = std.StaticStringMap(void).initComptime([_]struct { []const u8, void }{ + .{ "ac", {} }, + .{ "com.ac", {} }, + .{ "edu.ac", {} }, + .{ "gov.ac", {} }, + .{ "mil.ac", {} }, + .{ "net.ac", {} }, + .{ "org.ac", {} }, + .{ "ad", {} }, + .{ "ae", {} }, + .{ "ac.ae", {} }, + .{ "co.ae", {} }, + .{ "gov.ae", {} }, + .{ "mil.ae", {} }, + .{ "net.ae", {} }, + .{ "org.ae", {} }, + .{ "sch.ae", {} }, + .{ "aero", {} }, + .{ "airline.aero", {} }, + .{ "airport.aero", {} }, + .{ "accident-investigation.aero", {} }, + .{ "accident-prevention.aero", {} }, + .{ "aerobatic.aero", {} }, + .{ "aeroclub.aero", {} }, + .{ "aerodrome.aero", {} }, + .{ "agents.aero", {} }, + .{ "air-surveillance.aero", {} }, + .{ "air-traffic-control.aero", {} }, + .{ "aircraft.aero", {} }, + .{ "airtraffic.aero", {} }, + .{ "ambulance.aero", {} }, + .{ "association.aero", {} }, + .{ "author.aero", {} }, + .{ "ballooning.aero", {} }, + .{ "broker.aero", {} }, + .{ "caa.aero", {} }, + .{ "cargo.aero", {} }, + .{ "catering.aero", {} }, + .{ "certification.aero", {} }, + .{ "championship.aero", {} }, + .{ "charter.aero", {} }, + .{ "civilaviation.aero", {} }, + .{ "club.aero", {} }, + .{ "conference.aero", {} }, + .{ "consultant.aero", {} }, + .{ "consulting.aero", {} }, + .{ "control.aero", {} }, + .{ "council.aero", {} }, + .{ "crew.aero", {} }, + .{ "design.aero", {} }, + .{ "dgca.aero", {} }, + .{ "educator.aero", {} }, + .{ "emergency.aero", {} }, + .{ "engine.aero", {} }, + .{ "engineer.aero", {} }, + .{ "entertainment.aero", {} }, + .{ "equipment.aero", {} }, + .{ "exchange.aero", {} }, + .{ "express.aero", {} }, + .{ "federation.aero", {} }, + .{ "flight.aero", {} }, + .{ "freight.aero", {} }, + .{ "fuel.aero", {} }, + .{ "gliding.aero", {} }, + .{ "government.aero", {} }, + .{ "groundhandling.aero", {} }, + .{ "group.aero", {} }, + .{ "hanggliding.aero", {} }, + .{ "homebuilt.aero", {} }, + .{ "insurance.aero", {} }, + .{ "journal.aero", {} }, + .{ "journalist.aero", {} }, + .{ "leasing.aero", {} }, + .{ "logistics.aero", {} }, + .{ "magazine.aero", {} }, + .{ "maintenance.aero", {} }, + .{ "marketplace.aero", {} }, + .{ "media.aero", {} }, + .{ "microlight.aero", {} }, + .{ "modelling.aero", {} }, + .{ "navigation.aero", {} }, + .{ "parachuting.aero", {} }, + .{ "paragliding.aero", {} }, + .{ "passenger-association.aero", {} }, + .{ "pilot.aero", {} }, + .{ "press.aero", {} }, + .{ "production.aero", {} }, + .{ "recreation.aero", {} }, + .{ "repbody.aero", {} }, + .{ "res.aero", {} }, + .{ "research.aero", {} }, + .{ "rotorcraft.aero", {} }, + .{ "safety.aero", {} }, + .{ "scientist.aero", {} }, + .{ "services.aero", {} }, + .{ "show.aero", {} }, + .{ "skydiving.aero", {} }, + .{ "software.aero", {} }, + .{ "student.aero", {} }, + .{ "taxi.aero", {} }, + .{ "trader.aero", {} }, + .{ "trading.aero", {} }, + .{ "trainer.aero", {} }, + .{ "union.aero", {} }, + .{ "workinggroup.aero", {} }, + .{ "works.aero", {} }, + .{ "af", {} }, + .{ "com.af", {} }, + .{ "edu.af", {} }, + .{ "gov.af", {} }, + .{ "net.af", {} }, + .{ "org.af", {} }, + .{ "ag", {} }, + .{ "co.ag", {} }, + .{ "com.ag", {} }, + .{ "net.ag", {} }, + .{ "nom.ag", {} }, + .{ "org.ag", {} }, + .{ "ai", {} }, + .{ "com.ai", {} }, + .{ "net.ai", {} }, + .{ "off.ai", {} }, + .{ "org.ai", {} }, + .{ "al", {} }, + .{ "com.al", {} }, + .{ "edu.al", {} }, + .{ "gov.al", {} }, + .{ "mil.al", {} }, + .{ "net.al", {} }, + .{ "org.al", {} }, + .{ "am", {} }, + .{ "co.am", {} }, + .{ "com.am", {} }, + .{ "commune.am", {} }, + .{ "net.am", {} }, + .{ "org.am", {} }, + .{ "ao", {} }, + .{ "co.ao", {} }, + .{ "ed.ao", {} }, + .{ "edu.ao", {} }, + .{ "gov.ao", {} }, + .{ "gv.ao", {} }, + .{ "it.ao", {} }, + .{ "og.ao", {} }, + .{ "org.ao", {} }, + .{ "pb.ao", {} }, + .{ "aq", {} }, + .{ "ar", {} }, + .{ "bet.ar", {} }, + .{ "com.ar", {} }, + .{ "coop.ar", {} }, + .{ "edu.ar", {} }, + .{ "gob.ar", {} }, + .{ "gov.ar", {} }, + .{ "int.ar", {} }, + .{ "mil.ar", {} }, + .{ "musica.ar", {} }, + .{ "mutual.ar", {} }, + .{ "net.ar", {} }, + .{ "org.ar", {} }, + .{ "senasa.ar", {} }, + .{ "tur.ar", {} }, + .{ "arpa", {} }, + .{ "e164.arpa", {} }, + .{ "home.arpa", {} }, + .{ "in-addr.arpa", {} }, + .{ "ip6.arpa", {} }, + .{ "iris.arpa", {} }, + .{ "uri.arpa", {} }, + .{ "urn.arpa", {} }, + .{ "as", {} }, + .{ "gov.as", {} }, + .{ "asia", {} }, + .{ "at", {} }, + .{ "ac.at", {} }, + .{ "sth.ac.at", {} }, + .{ "co.at", {} }, + .{ "gv.at", {} }, + .{ "or.at", {} }, + .{ "au", {} }, + .{ "asn.au", {} }, + .{ "com.au", {} }, + .{ "edu.au", {} }, + .{ "gov.au", {} }, + .{ "id.au", {} }, + .{ "net.au", {} }, + .{ "org.au", {} }, + .{ "conf.au", {} }, + .{ "oz.au", {} }, + .{ "act.au", {} }, + .{ "nsw.au", {} }, + .{ "nt.au", {} }, + .{ "qld.au", {} }, + .{ "sa.au", {} }, + .{ "tas.au", {} }, + .{ "vic.au", {} }, + .{ "wa.au", {} }, + .{ "act.edu.au", {} }, + .{ "catholic.edu.au", {} }, + .{ "nsw.edu.au", {} }, + .{ "nt.edu.au", {} }, + .{ "qld.edu.au", {} }, + .{ "sa.edu.au", {} }, + .{ "tas.edu.au", {} }, + .{ "vic.edu.au", {} }, + .{ "wa.edu.au", {} }, + .{ "qld.gov.au", {} }, + .{ "sa.gov.au", {} }, + .{ "tas.gov.au", {} }, + .{ "vic.gov.au", {} }, + .{ "wa.gov.au", {} }, + .{ "schools.nsw.edu.au", {} }, + .{ "aw", {} }, + .{ "com.aw", {} }, + .{ "ax", {} }, + .{ "az", {} }, + .{ "biz.az", {} }, + .{ "co.az", {} }, + .{ "com.az", {} }, + .{ "edu.az", {} }, + .{ "gov.az", {} }, + .{ "info.az", {} }, + .{ "int.az", {} }, + .{ "mil.az", {} }, + .{ "name.az", {} }, + .{ "net.az", {} }, + .{ "org.az", {} }, + .{ "pp.az", {} }, + .{ "pro.az", {} }, + .{ "ba", {} }, + .{ "com.ba", {} }, + .{ "edu.ba", {} }, + .{ "gov.ba", {} }, + .{ "mil.ba", {} }, + .{ "net.ba", {} }, + .{ "org.ba", {} }, + .{ "bb", {} }, + .{ "biz.bb", {} }, + .{ "co.bb", {} }, + .{ "com.bb", {} }, + .{ "edu.bb", {} }, + .{ "gov.bb", {} }, + .{ "info.bb", {} }, + .{ "net.bb", {} }, + .{ "org.bb", {} }, + .{ "store.bb", {} }, + .{ "tv.bb", {} }, + .{ "*.bd", {} }, + .{ "be", {} }, + .{ "ac.be", {} }, + .{ "bf", {} }, + .{ "gov.bf", {} }, + .{ "bg", {} }, + .{ "0.bg", {} }, + .{ "1.bg", {} }, + .{ "2.bg", {} }, + .{ "3.bg", {} }, + .{ "4.bg", {} }, + .{ "5.bg", {} }, + .{ "6.bg", {} }, + .{ "7.bg", {} }, + .{ "8.bg", {} }, + .{ "9.bg", {} }, + .{ "a.bg", {} }, + .{ "b.bg", {} }, + .{ "c.bg", {} }, + .{ "d.bg", {} }, + .{ "e.bg", {} }, + .{ "f.bg", {} }, + .{ "g.bg", {} }, + .{ "h.bg", {} }, + .{ "i.bg", {} }, + .{ "j.bg", {} }, + .{ "k.bg", {} }, + .{ "l.bg", {} }, + .{ "m.bg", {} }, + .{ "n.bg", {} }, + .{ "o.bg", {} }, + .{ "p.bg", {} }, + .{ "q.bg", {} }, + .{ "r.bg", {} }, + .{ "s.bg", {} }, + .{ "t.bg", {} }, + .{ "u.bg", {} }, + .{ "v.bg", {} }, + .{ "w.bg", {} }, + .{ "x.bg", {} }, + .{ "y.bg", {} }, + .{ "z.bg", {} }, + .{ "bh", {} }, + .{ "com.bh", {} }, + .{ "edu.bh", {} }, + .{ "gov.bh", {} }, + .{ "net.bh", {} }, + .{ "org.bh", {} }, + .{ "bi", {} }, + .{ "co.bi", {} }, + .{ "com.bi", {} }, + .{ "edu.bi", {} }, + .{ "or.bi", {} }, + .{ "org.bi", {} }, + .{ "biz", {} }, + .{ "bj", {} }, + .{ "africa.bj", {} }, + .{ "agro.bj", {} }, + .{ "architectes.bj", {} }, + .{ "assur.bj", {} }, + .{ "avocats.bj", {} }, + .{ "co.bj", {} }, + .{ "com.bj", {} }, + .{ "eco.bj", {} }, + .{ "econo.bj", {} }, + .{ "edu.bj", {} }, + .{ "info.bj", {} }, + .{ "loisirs.bj", {} }, + .{ "money.bj", {} }, + .{ "net.bj", {} }, + .{ "org.bj", {} }, + .{ "ote.bj", {} }, + .{ "restaurant.bj", {} }, + .{ "resto.bj", {} }, + .{ "tourism.bj", {} }, + .{ "univ.bj", {} }, + .{ "bm", {} }, + .{ "com.bm", {} }, + .{ "edu.bm", {} }, + .{ "gov.bm", {} }, + .{ "net.bm", {} }, + .{ "org.bm", {} }, + .{ "bn", {} }, + .{ "com.bn", {} }, + .{ "edu.bn", {} }, + .{ "gov.bn", {} }, + .{ "net.bn", {} }, + .{ "org.bn", {} }, + .{ "bo", {} }, + .{ "com.bo", {} }, + .{ "edu.bo", {} }, + .{ "gob.bo", {} }, + .{ "int.bo", {} }, + .{ "mil.bo", {} }, + .{ "net.bo", {} }, + .{ "org.bo", {} }, + .{ "tv.bo", {} }, + .{ "web.bo", {} }, + .{ "academia.bo", {} }, + .{ "agro.bo", {} }, + .{ "arte.bo", {} }, + .{ "blog.bo", {} }, + .{ "bolivia.bo", {} }, + .{ "ciencia.bo", {} }, + .{ "cooperativa.bo", {} }, + .{ "democracia.bo", {} }, + .{ "deporte.bo", {} }, + .{ "ecologia.bo", {} }, + .{ "economia.bo", {} }, + .{ "empresa.bo", {} }, + .{ "indigena.bo", {} }, + .{ "industria.bo", {} }, + .{ "info.bo", {} }, + .{ "medicina.bo", {} }, + .{ "movimiento.bo", {} }, + .{ "musica.bo", {} }, + .{ "natural.bo", {} }, + .{ "nombre.bo", {} }, + .{ "noticias.bo", {} }, + .{ "patria.bo", {} }, + .{ "plurinacional.bo", {} }, + .{ "politica.bo", {} }, + .{ "profesional.bo", {} }, + .{ "pueblo.bo", {} }, + .{ "revista.bo", {} }, + .{ "salud.bo", {} }, + .{ "tecnologia.bo", {} }, + .{ "tksat.bo", {} }, + .{ "transporte.bo", {} }, + .{ "wiki.bo", {} }, + .{ "br", {} }, + .{ "9guacu.br", {} }, + .{ "abc.br", {} }, + .{ "adm.br", {} }, + .{ "adv.br", {} }, + .{ "agr.br", {} }, + .{ "aju.br", {} }, + .{ "am.br", {} }, + .{ "anani.br", {} }, + .{ "aparecida.br", {} }, + .{ "app.br", {} }, + .{ "arq.br", {} }, + .{ "art.br", {} }, + .{ "ato.br", {} }, + .{ "b.br", {} }, + .{ "barueri.br", {} }, + .{ "belem.br", {} }, + .{ "bet.br", {} }, + .{ "bhz.br", {} }, + .{ "bib.br", {} }, + .{ "bio.br", {} }, + .{ "blog.br", {} }, + .{ "bmd.br", {} }, + .{ "boavista.br", {} }, + .{ "bsb.br", {} }, + .{ "campinagrande.br", {} }, + .{ "campinas.br", {} }, + .{ "caxias.br", {} }, + .{ "cim.br", {} }, + .{ "cng.br", {} }, + .{ "cnt.br", {} }, + .{ "com.br", {} }, + .{ "contagem.br", {} }, + .{ "coop.br", {} }, + .{ "coz.br", {} }, + .{ "cri.br", {} }, + .{ "cuiaba.br", {} }, + .{ "curitiba.br", {} }, + .{ "def.br", {} }, + .{ "des.br", {} }, + .{ "det.br", {} }, + .{ "dev.br", {} }, + .{ "ecn.br", {} }, + .{ "eco.br", {} }, + .{ "edu.br", {} }, + .{ "emp.br", {} }, + .{ "enf.br", {} }, + .{ "eng.br", {} }, + .{ "esp.br", {} }, + .{ "etc.br", {} }, + .{ "eti.br", {} }, + .{ "far.br", {} }, + .{ "feira.br", {} }, + .{ "flog.br", {} }, + .{ "floripa.br", {} }, + .{ "fm.br", {} }, + .{ "fnd.br", {} }, + .{ "fortal.br", {} }, + .{ "fot.br", {} }, + .{ "foz.br", {} }, + .{ "fst.br", {} }, + .{ "g12.br", {} }, + .{ "geo.br", {} }, + .{ "ggf.br", {} }, + .{ "goiania.br", {} }, + .{ "gov.br", {} }, + .{ "ac.gov.br", {} }, + .{ "al.gov.br", {} }, + .{ "am.gov.br", {} }, + .{ "ap.gov.br", {} }, + .{ "ba.gov.br", {} }, + .{ "ce.gov.br", {} }, + .{ "df.gov.br", {} }, + .{ "es.gov.br", {} }, + .{ "go.gov.br", {} }, + .{ "ma.gov.br", {} }, + .{ "mg.gov.br", {} }, + .{ "ms.gov.br", {} }, + .{ "mt.gov.br", {} }, + .{ "pa.gov.br", {} }, + .{ "pb.gov.br", {} }, + .{ "pe.gov.br", {} }, + .{ "pi.gov.br", {} }, + .{ "pr.gov.br", {} }, + .{ "rj.gov.br", {} }, + .{ "rn.gov.br", {} }, + .{ "ro.gov.br", {} }, + .{ "rr.gov.br", {} }, + .{ "rs.gov.br", {} }, + .{ "sc.gov.br", {} }, + .{ "se.gov.br", {} }, + .{ "sp.gov.br", {} }, + .{ "to.gov.br", {} }, + .{ "gru.br", {} }, + .{ "imb.br", {} }, + .{ "ind.br", {} }, + .{ "inf.br", {} }, + .{ "jab.br", {} }, + .{ "jampa.br", {} }, + .{ "jdf.br", {} }, + .{ "joinville.br", {} }, + .{ "jor.br", {} }, + .{ "jus.br", {} }, + .{ "leg.br", {} }, + .{ "leilao.br", {} }, + .{ "lel.br", {} }, + .{ "log.br", {} }, + .{ "londrina.br", {} }, + .{ "macapa.br", {} }, + .{ "maceio.br", {} }, + .{ "manaus.br", {} }, + .{ "maringa.br", {} }, + .{ "mat.br", {} }, + .{ "med.br", {} }, + .{ "mil.br", {} }, + .{ "morena.br", {} }, + .{ "mp.br", {} }, + .{ "mus.br", {} }, + .{ "natal.br", {} }, + .{ "net.br", {} }, + .{ "niteroi.br", {} }, + .{ "*.nom.br", {} }, + .{ "not.br", {} }, + .{ "ntr.br", {} }, + .{ "odo.br", {} }, + .{ "ong.br", {} }, + .{ "org.br", {} }, + .{ "osasco.br", {} }, + .{ "palmas.br", {} }, + .{ "poa.br", {} }, + .{ "ppg.br", {} }, + .{ "pro.br", {} }, + .{ "psc.br", {} }, + .{ "psi.br", {} }, + .{ "pvh.br", {} }, + .{ "qsl.br", {} }, + .{ "radio.br", {} }, + .{ "rec.br", {} }, + .{ "recife.br", {} }, + .{ "rep.br", {} }, + .{ "ribeirao.br", {} }, + .{ "rio.br", {} }, + .{ "riobranco.br", {} }, + .{ "riopreto.br", {} }, + .{ "salvador.br", {} }, + .{ "sampa.br", {} }, + .{ "santamaria.br", {} }, + .{ "santoandre.br", {} }, + .{ "saobernardo.br", {} }, + .{ "saogonca.br", {} }, + .{ "seg.br", {} }, + .{ "sjc.br", {} }, + .{ "slg.br", {} }, + .{ "slz.br", {} }, + .{ "sorocaba.br", {} }, + .{ "srv.br", {} }, + .{ "taxi.br", {} }, + .{ "tc.br", {} }, + .{ "tec.br", {} }, + .{ "teo.br", {} }, + .{ "the.br", {} }, + .{ "tmp.br", {} }, + .{ "trd.br", {} }, + .{ "tur.br", {} }, + .{ "tv.br", {} }, + .{ "udi.br", {} }, + .{ "vet.br", {} }, + .{ "vix.br", {} }, + .{ "vlog.br", {} }, + .{ "wiki.br", {} }, + .{ "zlg.br", {} }, + .{ "bs", {} }, + .{ "com.bs", {} }, + .{ "edu.bs", {} }, + .{ "gov.bs", {} }, + .{ "net.bs", {} }, + .{ "org.bs", {} }, + .{ "bt", {} }, + .{ "com.bt", {} }, + .{ "edu.bt", {} }, + .{ "gov.bt", {} }, + .{ "net.bt", {} }, + .{ "org.bt", {} }, + .{ "bv", {} }, + .{ "bw", {} }, + .{ "ac.bw", {} }, + .{ "co.bw", {} }, + .{ "gov.bw", {} }, + .{ "net.bw", {} }, + .{ "org.bw", {} }, + .{ "by", {} }, + .{ "gov.by", {} }, + .{ "mil.by", {} }, + .{ "com.by", {} }, + .{ "of.by", {} }, + .{ "bz", {} }, + .{ "co.bz", {} }, + .{ "com.bz", {} }, + .{ "edu.bz", {} }, + .{ "gov.bz", {} }, + .{ "net.bz", {} }, + .{ "org.bz", {} }, + .{ "ca", {} }, + .{ "ab.ca", {} }, + .{ "bc.ca", {} }, + .{ "mb.ca", {} }, + .{ "nb.ca", {} }, + .{ "nf.ca", {} }, + .{ "nl.ca", {} }, + .{ "ns.ca", {} }, + .{ "nt.ca", {} }, + .{ "nu.ca", {} }, + .{ "on.ca", {} }, + .{ "pe.ca", {} }, + .{ "qc.ca", {} }, + .{ "sk.ca", {} }, + .{ "yk.ca", {} }, + .{ "gc.ca", {} }, + .{ "cat", {} }, + .{ "cc", {} }, + .{ "cd", {} }, + .{ "gov.cd", {} }, + .{ "cf", {} }, + .{ "cg", {} }, + .{ "ch", {} }, + .{ "ci", {} }, + .{ "ac.ci", {} }, + .{ "aéroport.ci", {} }, + .{ "asso.ci", {} }, + .{ "co.ci", {} }, + .{ "com.ci", {} }, + .{ "ed.ci", {} }, + .{ "edu.ci", {} }, + .{ "go.ci", {} }, + .{ "gouv.ci", {} }, + .{ "int.ci", {} }, + .{ "net.ci", {} }, + .{ "or.ci", {} }, + .{ "org.ci", {} }, + .{ "*.ck", {} }, + .{ "!www.ck", {} }, + .{ "cl", {} }, + .{ "co.cl", {} }, + .{ "gob.cl", {} }, + .{ "gov.cl", {} }, + .{ "mil.cl", {} }, + .{ "cm", {} }, + .{ "co.cm", {} }, + .{ "com.cm", {} }, + .{ "gov.cm", {} }, + .{ "net.cm", {} }, + .{ "cn", {} }, + .{ "ac.cn", {} }, + .{ "com.cn", {} }, + .{ "edu.cn", {} }, + .{ "gov.cn", {} }, + .{ "mil.cn", {} }, + .{ "net.cn", {} }, + .{ "org.cn", {} }, + .{ "公司.cn", {} }, + .{ "網絡.cn", {} }, + .{ "网络.cn", {} }, + .{ "ah.cn", {} }, + .{ "bj.cn", {} }, + .{ "cq.cn", {} }, + .{ "fj.cn", {} }, + .{ "gd.cn", {} }, + .{ "gs.cn", {} }, + .{ "gx.cn", {} }, + .{ "gz.cn", {} }, + .{ "ha.cn", {} }, + .{ "hb.cn", {} }, + .{ "he.cn", {} }, + .{ "hi.cn", {} }, + .{ "hk.cn", {} }, + .{ "hl.cn", {} }, + .{ "hn.cn", {} }, + .{ "jl.cn", {} }, + .{ "js.cn", {} }, + .{ "jx.cn", {} }, + .{ "ln.cn", {} }, + .{ "mo.cn", {} }, + .{ "nm.cn", {} }, + .{ "nx.cn", {} }, + .{ "qh.cn", {} }, + .{ "sc.cn", {} }, + .{ "sd.cn", {} }, + .{ "sh.cn", {} }, + .{ "sn.cn", {} }, + .{ "sx.cn", {} }, + .{ "tj.cn", {} }, + .{ "tw.cn", {} }, + .{ "xj.cn", {} }, + .{ "xz.cn", {} }, + .{ "yn.cn", {} }, + .{ "zj.cn", {} }, + .{ "co", {} }, + .{ "com.co", {} }, + .{ "edu.co", {} }, + .{ "gov.co", {} }, + .{ "mil.co", {} }, + .{ "net.co", {} }, + .{ "nom.co", {} }, + .{ "org.co", {} }, + .{ "com", {} }, + .{ "coop", {} }, + .{ "cr", {} }, + .{ "ac.cr", {} }, + .{ "co.cr", {} }, + .{ "ed.cr", {} }, + .{ "fi.cr", {} }, + .{ "go.cr", {} }, + .{ "or.cr", {} }, + .{ "sa.cr", {} }, + .{ "cu", {} }, + .{ "com.cu", {} }, + .{ "edu.cu", {} }, + .{ "gob.cu", {} }, + .{ "inf.cu", {} }, + .{ "nat.cu", {} }, + .{ "net.cu", {} }, + .{ "org.cu", {} }, + .{ "cv", {} }, + .{ "com.cv", {} }, + .{ "edu.cv", {} }, + .{ "id.cv", {} }, + .{ "int.cv", {} }, + .{ "net.cv", {} }, + .{ "nome.cv", {} }, + .{ "org.cv", {} }, + .{ "publ.cv", {} }, + .{ "cw", {} }, + .{ "com.cw", {} }, + .{ "edu.cw", {} }, + .{ "net.cw", {} }, + .{ "org.cw", {} }, + .{ "cx", {} }, + .{ "gov.cx", {} }, + .{ "cy", {} }, + .{ "ac.cy", {} }, + .{ "biz.cy", {} }, + .{ "com.cy", {} }, + .{ "ekloges.cy", {} }, + .{ "gov.cy", {} }, + .{ "ltd.cy", {} }, + .{ "mil.cy", {} }, + .{ "net.cy", {} }, + .{ "org.cy", {} }, + .{ "press.cy", {} }, + .{ "pro.cy", {} }, + .{ "tm.cy", {} }, + .{ "cz", {} }, + .{ "de", {} }, + .{ "dj", {} }, + .{ "dk", {} }, + .{ "dm", {} }, + .{ "co.dm", {} }, + .{ "com.dm", {} }, + .{ "edu.dm", {} }, + .{ "gov.dm", {} }, + .{ "net.dm", {} }, + .{ "org.dm", {} }, + .{ "do", {} }, + .{ "art.do", {} }, + .{ "com.do", {} }, + .{ "edu.do", {} }, + .{ "gob.do", {} }, + .{ "gov.do", {} }, + .{ "mil.do", {} }, + .{ "net.do", {} }, + .{ "org.do", {} }, + .{ "sld.do", {} }, + .{ "web.do", {} }, + .{ "dz", {} }, + .{ "art.dz", {} }, + .{ "asso.dz", {} }, + .{ "com.dz", {} }, + .{ "edu.dz", {} }, + .{ "gov.dz", {} }, + .{ "net.dz", {} }, + .{ "org.dz", {} }, + .{ "pol.dz", {} }, + .{ "soc.dz", {} }, + .{ "tm.dz", {} }, + .{ "ec", {} }, + .{ "com.ec", {} }, + .{ "edu.ec", {} }, + .{ "fin.ec", {} }, + .{ "gob.ec", {} }, + .{ "gov.ec", {} }, + .{ "info.ec", {} }, + .{ "k12.ec", {} }, + .{ "med.ec", {} }, + .{ "mil.ec", {} }, + .{ "net.ec", {} }, + .{ "org.ec", {} }, + .{ "pro.ec", {} }, + .{ "edu", {} }, + .{ "ee", {} }, + .{ "aip.ee", {} }, + .{ "com.ee", {} }, + .{ "edu.ee", {} }, + .{ "fie.ee", {} }, + .{ "gov.ee", {} }, + .{ "lib.ee", {} }, + .{ "med.ee", {} }, + .{ "org.ee", {} }, + .{ "pri.ee", {} }, + .{ "riik.ee", {} }, + .{ "eg", {} }, + .{ "ac.eg", {} }, + .{ "com.eg", {} }, + .{ "edu.eg", {} }, + .{ "eun.eg", {} }, + .{ "gov.eg", {} }, + .{ "info.eg", {} }, + .{ "me.eg", {} }, + .{ "mil.eg", {} }, + .{ "name.eg", {} }, + .{ "net.eg", {} }, + .{ "org.eg", {} }, + .{ "sci.eg", {} }, + .{ "sport.eg", {} }, + .{ "tv.eg", {} }, + .{ "*.er", {} }, + .{ "es", {} }, + .{ "com.es", {} }, + .{ "edu.es", {} }, + .{ "gob.es", {} }, + .{ "nom.es", {} }, + .{ "org.es", {} }, + .{ "et", {} }, + .{ "biz.et", {} }, + .{ "com.et", {} }, + .{ "edu.et", {} }, + .{ "gov.et", {} }, + .{ "info.et", {} }, + .{ "name.et", {} }, + .{ "net.et", {} }, + .{ "org.et", {} }, + .{ "eu", {} }, + .{ "fi", {} }, + .{ "aland.fi", {} }, + .{ "fj", {} }, + .{ "ac.fj", {} }, + .{ "biz.fj", {} }, + .{ "com.fj", {} }, + .{ "gov.fj", {} }, + .{ "info.fj", {} }, + .{ "mil.fj", {} }, + .{ "name.fj", {} }, + .{ "net.fj", {} }, + .{ "org.fj", {} }, + .{ "pro.fj", {} }, + .{ "*.fk", {} }, + .{ "fm", {} }, + .{ "com.fm", {} }, + .{ "edu.fm", {} }, + .{ "net.fm", {} }, + .{ "org.fm", {} }, + .{ "fo", {} }, + .{ "fr", {} }, + .{ "asso.fr", {} }, + .{ "com.fr", {} }, + .{ "gouv.fr", {} }, + .{ "nom.fr", {} }, + .{ "prd.fr", {} }, + .{ "tm.fr", {} }, + .{ "avoues.fr", {} }, + .{ "cci.fr", {} }, + .{ "greta.fr", {} }, + .{ "huissier-justice.fr", {} }, + .{ "ga", {} }, + .{ "gb", {} }, + .{ "gd", {} }, + .{ "edu.gd", {} }, + .{ "gov.gd", {} }, + .{ "ge", {} }, + .{ "com.ge", {} }, + .{ "edu.ge", {} }, + .{ "gov.ge", {} }, + .{ "net.ge", {} }, + .{ "org.ge", {} }, + .{ "pvt.ge", {} }, + .{ "school.ge", {} }, + .{ "gf", {} }, + .{ "gg", {} }, + .{ "co.gg", {} }, + .{ "net.gg", {} }, + .{ "org.gg", {} }, + .{ "gh", {} }, + .{ "com.gh", {} }, + .{ "edu.gh", {} }, + .{ "gov.gh", {} }, + .{ "mil.gh", {} }, + .{ "org.gh", {} }, + .{ "gi", {} }, + .{ "com.gi", {} }, + .{ "edu.gi", {} }, + .{ "gov.gi", {} }, + .{ "ltd.gi", {} }, + .{ "mod.gi", {} }, + .{ "org.gi", {} }, + .{ "gl", {} }, + .{ "co.gl", {} }, + .{ "com.gl", {} }, + .{ "edu.gl", {} }, + .{ "net.gl", {} }, + .{ "org.gl", {} }, + .{ "gm", {} }, + .{ "gn", {} }, + .{ "ac.gn", {} }, + .{ "com.gn", {} }, + .{ "edu.gn", {} }, + .{ "gov.gn", {} }, + .{ "net.gn", {} }, + .{ "org.gn", {} }, + .{ "gov", {} }, + .{ "gp", {} }, + .{ "asso.gp", {} }, + .{ "com.gp", {} }, + .{ "edu.gp", {} }, + .{ "mobi.gp", {} }, + .{ "net.gp", {} }, + .{ "org.gp", {} }, + .{ "gq", {} }, + .{ "gr", {} }, + .{ "com.gr", {} }, + .{ "edu.gr", {} }, + .{ "gov.gr", {} }, + .{ "net.gr", {} }, + .{ "org.gr", {} }, + .{ "gs", {} }, + .{ "gt", {} }, + .{ "com.gt", {} }, + .{ "edu.gt", {} }, + .{ "gob.gt", {} }, + .{ "ind.gt", {} }, + .{ "mil.gt", {} }, + .{ "net.gt", {} }, + .{ "org.gt", {} }, + .{ "gu", {} }, + .{ "com.gu", {} }, + .{ "edu.gu", {} }, + .{ "gov.gu", {} }, + .{ "guam.gu", {} }, + .{ "info.gu", {} }, + .{ "net.gu", {} }, + .{ "org.gu", {} }, + .{ "web.gu", {} }, + .{ "gw", {} }, + .{ "gy", {} }, + .{ "co.gy", {} }, + .{ "com.gy", {} }, + .{ "edu.gy", {} }, + .{ "gov.gy", {} }, + .{ "net.gy", {} }, + .{ "org.gy", {} }, + .{ "hk", {} }, + .{ "com.hk", {} }, + .{ "edu.hk", {} }, + .{ "gov.hk", {} }, + .{ "idv.hk", {} }, + .{ "net.hk", {} }, + .{ "org.hk", {} }, + .{ "个人.hk", {} }, + .{ "個人.hk", {} }, + .{ "公司.hk", {} }, + .{ "政府.hk", {} }, + .{ "敎育.hk", {} }, + .{ "教育.hk", {} }, + .{ "箇人.hk", {} }, + .{ "組織.hk", {} }, + .{ "組织.hk", {} }, + .{ "網絡.hk", {} }, + .{ "網络.hk", {} }, + .{ "组織.hk", {} }, + .{ "组织.hk", {} }, + .{ "网絡.hk", {} }, + .{ "网络.hk", {} }, + .{ "hm", {} }, + .{ "hn", {} }, + .{ "com.hn", {} }, + .{ "edu.hn", {} }, + .{ "gob.hn", {} }, + .{ "mil.hn", {} }, + .{ "net.hn", {} }, + .{ "org.hn", {} }, + .{ "hr", {} }, + .{ "com.hr", {} }, + .{ "from.hr", {} }, + .{ "iz.hr", {} }, + .{ "name.hr", {} }, + .{ "ht", {} }, + .{ "adult.ht", {} }, + .{ "art.ht", {} }, + .{ "asso.ht", {} }, + .{ "com.ht", {} }, + .{ "coop.ht", {} }, + .{ "edu.ht", {} }, + .{ "firm.ht", {} }, + .{ "gouv.ht", {} }, + .{ "info.ht", {} }, + .{ "med.ht", {} }, + .{ "net.ht", {} }, + .{ "org.ht", {} }, + .{ "perso.ht", {} }, + .{ "pol.ht", {} }, + .{ "pro.ht", {} }, + .{ "rel.ht", {} }, + .{ "shop.ht", {} }, + .{ "hu", {} }, + .{ "2000.hu", {} }, + .{ "agrar.hu", {} }, + .{ "bolt.hu", {} }, + .{ "casino.hu", {} }, + .{ "city.hu", {} }, + .{ "co.hu", {} }, + .{ "erotica.hu", {} }, + .{ "erotika.hu", {} }, + .{ "film.hu", {} }, + .{ "forum.hu", {} }, + .{ "games.hu", {} }, + .{ "hotel.hu", {} }, + .{ "info.hu", {} }, + .{ "ingatlan.hu", {} }, + .{ "jogasz.hu", {} }, + .{ "konyvelo.hu", {} }, + .{ "lakas.hu", {} }, + .{ "media.hu", {} }, + .{ "news.hu", {} }, + .{ "org.hu", {} }, + .{ "priv.hu", {} }, + .{ "reklam.hu", {} }, + .{ "sex.hu", {} }, + .{ "shop.hu", {} }, + .{ "sport.hu", {} }, + .{ "suli.hu", {} }, + .{ "szex.hu", {} }, + .{ "tm.hu", {} }, + .{ "tozsde.hu", {} }, + .{ "utazas.hu", {} }, + .{ "video.hu", {} }, + .{ "id", {} }, + .{ "ac.id", {} }, + .{ "biz.id", {} }, + .{ "co.id", {} }, + .{ "desa.id", {} }, + .{ "go.id", {} }, + .{ "mil.id", {} }, + .{ "my.id", {} }, + .{ "net.id", {} }, + .{ "or.id", {} }, + .{ "ponpes.id", {} }, + .{ "sch.id", {} }, + .{ "web.id", {} }, + .{ "ie", {} }, + .{ "gov.ie", {} }, + .{ "il", {} }, + .{ "ac.il", {} }, + .{ "co.il", {} }, + .{ "gov.il", {} }, + .{ "idf.il", {} }, + .{ "k12.il", {} }, + .{ "muni.il", {} }, + .{ "net.il", {} }, + .{ "org.il", {} }, + .{ "ישראל", {} }, + .{ "אקדמיה.ישראל", {} }, + .{ "ישוב.ישראל", {} }, + .{ "צהל.ישראל", {} }, + .{ "ממשל.ישראל", {} }, + .{ "im", {} }, + .{ "ac.im", {} }, + .{ "co.im", {} }, + .{ "ltd.co.im", {} }, + .{ "plc.co.im", {} }, + .{ "com.im", {} }, + .{ "net.im", {} }, + .{ "org.im", {} }, + .{ "tt.im", {} }, + .{ "tv.im", {} }, + .{ "in", {} }, + .{ "5g.in", {} }, + .{ "6g.in", {} }, + .{ "ac.in", {} }, + .{ "ai.in", {} }, + .{ "am.in", {} }, + .{ "bihar.in", {} }, + .{ "biz.in", {} }, + .{ "business.in", {} }, + .{ "ca.in", {} }, + .{ "cn.in", {} }, + .{ "co.in", {} }, + .{ "com.in", {} }, + .{ "coop.in", {} }, + .{ "cs.in", {} }, + .{ "delhi.in", {} }, + .{ "dr.in", {} }, + .{ "edu.in", {} }, + .{ "er.in", {} }, + .{ "firm.in", {} }, + .{ "gen.in", {} }, + .{ "gov.in", {} }, + .{ "gujarat.in", {} }, + .{ "ind.in", {} }, + .{ "info.in", {} }, + .{ "int.in", {} }, + .{ "internet.in", {} }, + .{ "io.in", {} }, + .{ "me.in", {} }, + .{ "mil.in", {} }, + .{ "net.in", {} }, + .{ "nic.in", {} }, + .{ "org.in", {} }, + .{ "pg.in", {} }, + .{ "post.in", {} }, + .{ "pro.in", {} }, + .{ "res.in", {} }, + .{ "travel.in", {} }, + .{ "tv.in", {} }, + .{ "uk.in", {} }, + .{ "up.in", {} }, + .{ "us.in", {} }, + .{ "info", {} }, + .{ "int", {} }, + .{ "eu.int", {} }, + .{ "io", {} }, + .{ "co.io", {} }, + .{ "com.io", {} }, + .{ "edu.io", {} }, + .{ "gov.io", {} }, + .{ "mil.io", {} }, + .{ "net.io", {} }, + .{ "nom.io", {} }, + .{ "org.io", {} }, + .{ "iq", {} }, + .{ "com.iq", {} }, + .{ "edu.iq", {} }, + .{ "gov.iq", {} }, + .{ "mil.iq", {} }, + .{ "net.iq", {} }, + .{ "org.iq", {} }, + .{ "ir", {} }, + .{ "ac.ir", {} }, + .{ "co.ir", {} }, + .{ "gov.ir", {} }, + .{ "id.ir", {} }, + .{ "net.ir", {} }, + .{ "org.ir", {} }, + .{ "sch.ir", {} }, + .{ "ایران.ir", {} }, + .{ "ايران.ir", {} }, + .{ "is", {} }, + .{ "it", {} }, + .{ "edu.it", {} }, + .{ "gov.it", {} }, + .{ "abr.it", {} }, + .{ "abruzzo.it", {} }, + .{ "aosta-valley.it", {} }, + .{ "aostavalley.it", {} }, + .{ "bas.it", {} }, + .{ "basilicata.it", {} }, + .{ "cal.it", {} }, + .{ "calabria.it", {} }, + .{ "cam.it", {} }, + .{ "campania.it", {} }, + .{ "emilia-romagna.it", {} }, + .{ "emiliaromagna.it", {} }, + .{ "emr.it", {} }, + .{ "friuli-v-giulia.it", {} }, + .{ "friuli-ve-giulia.it", {} }, + .{ "friuli-vegiulia.it", {} }, + .{ "friuli-venezia-giulia.it", {} }, + .{ "friuli-veneziagiulia.it", {} }, + .{ "friuli-vgiulia.it", {} }, + .{ "friuliv-giulia.it", {} }, + .{ "friulive-giulia.it", {} }, + .{ "friulivegiulia.it", {} }, + .{ "friulivenezia-giulia.it", {} }, + .{ "friuliveneziagiulia.it", {} }, + .{ "friulivgiulia.it", {} }, + .{ "fvg.it", {} }, + .{ "laz.it", {} }, + .{ "lazio.it", {} }, + .{ "lig.it", {} }, + .{ "liguria.it", {} }, + .{ "lom.it", {} }, + .{ "lombardia.it", {} }, + .{ "lombardy.it", {} }, + .{ "lucania.it", {} }, + .{ "mar.it", {} }, + .{ "marche.it", {} }, + .{ "mol.it", {} }, + .{ "molise.it", {} }, + .{ "piedmont.it", {} }, + .{ "piemonte.it", {} }, + .{ "pmn.it", {} }, + .{ "pug.it", {} }, + .{ "puglia.it", {} }, + .{ "sar.it", {} }, + .{ "sardegna.it", {} }, + .{ "sardinia.it", {} }, + .{ "sic.it", {} }, + .{ "sicilia.it", {} }, + .{ "sicily.it", {} }, + .{ "taa.it", {} }, + .{ "tos.it", {} }, + .{ "toscana.it", {} }, + .{ "trentin-sud-tirol.it", {} }, + .{ "trentin-süd-tirol.it", {} }, + .{ "trentin-sudtirol.it", {} }, + .{ "trentin-südtirol.it", {} }, + .{ "trentin-sued-tirol.it", {} }, + .{ "trentin-suedtirol.it", {} }, + .{ "trentino.it", {} }, + .{ "trentino-a-adige.it", {} }, + .{ "trentino-aadige.it", {} }, + .{ "trentino-alto-adige.it", {} }, + .{ "trentino-altoadige.it", {} }, + .{ "trentino-s-tirol.it", {} }, + .{ "trentino-stirol.it", {} }, + .{ "trentino-sud-tirol.it", {} }, + .{ "trentino-süd-tirol.it", {} }, + .{ "trentino-sudtirol.it", {} }, + .{ "trentino-südtirol.it", {} }, + .{ "trentino-sued-tirol.it", {} }, + .{ "trentino-suedtirol.it", {} }, + .{ "trentinoa-adige.it", {} }, + .{ "trentinoaadige.it", {} }, + .{ "trentinoalto-adige.it", {} }, + .{ "trentinoaltoadige.it", {} }, + .{ "trentinos-tirol.it", {} }, + .{ "trentinostirol.it", {} }, + .{ "trentinosud-tirol.it", {} }, + .{ "trentinosüd-tirol.it", {} }, + .{ "trentinosudtirol.it", {} }, + .{ "trentinosüdtirol.it", {} }, + .{ "trentinosued-tirol.it", {} }, + .{ "trentinosuedtirol.it", {} }, + .{ "trentinsud-tirol.it", {} }, + .{ "trentinsüd-tirol.it", {} }, + .{ "trentinsudtirol.it", {} }, + .{ "trentinsüdtirol.it", {} }, + .{ "trentinsued-tirol.it", {} }, + .{ "trentinsuedtirol.it", {} }, + .{ "tuscany.it", {} }, + .{ "umb.it", {} }, + .{ "umbria.it", {} }, + .{ "val-d-aosta.it", {} }, + .{ "val-daosta.it", {} }, + .{ "vald-aosta.it", {} }, + .{ "valdaosta.it", {} }, + .{ "valle-aosta.it", {} }, + .{ "valle-d-aosta.it", {} }, + .{ "valle-daosta.it", {} }, + .{ "valleaosta.it", {} }, + .{ "valled-aosta.it", {} }, + .{ "valledaosta.it", {} }, + .{ "vallee-aoste.it", {} }, + .{ "vallée-aoste.it", {} }, + .{ "vallee-d-aoste.it", {} }, + .{ "vallée-d-aoste.it", {} }, + .{ "valleeaoste.it", {} }, + .{ "valléeaoste.it", {} }, + .{ "valleedaoste.it", {} }, + .{ "valléedaoste.it", {} }, + .{ "vao.it", {} }, + .{ "vda.it", {} }, + .{ "ven.it", {} }, + .{ "veneto.it", {} }, + .{ "ag.it", {} }, + .{ "agrigento.it", {} }, + .{ "al.it", {} }, + .{ "alessandria.it", {} }, + .{ "alto-adige.it", {} }, + .{ "altoadige.it", {} }, + .{ "an.it", {} }, + .{ "ancona.it", {} }, + .{ "andria-barletta-trani.it", {} }, + .{ "andria-trani-barletta.it", {} }, + .{ "andriabarlettatrani.it", {} }, + .{ "andriatranibarletta.it", {} }, + .{ "ao.it", {} }, + .{ "aosta.it", {} }, + .{ "aoste.it", {} }, + .{ "ap.it", {} }, + .{ "aq.it", {} }, + .{ "aquila.it", {} }, + .{ "ar.it", {} }, + .{ "arezzo.it", {} }, + .{ "ascoli-piceno.it", {} }, + .{ "ascolipiceno.it", {} }, + .{ "asti.it", {} }, + .{ "at.it", {} }, + .{ "av.it", {} }, + .{ "avellino.it", {} }, + .{ "ba.it", {} }, + .{ "balsan.it", {} }, + .{ "balsan-sudtirol.it", {} }, + .{ "balsan-südtirol.it", {} }, + .{ "balsan-suedtirol.it", {} }, + .{ "bari.it", {} }, + .{ "barletta-trani-andria.it", {} }, + .{ "barlettatraniandria.it", {} }, + .{ "belluno.it", {} }, + .{ "benevento.it", {} }, + .{ "bergamo.it", {} }, + .{ "bg.it", {} }, + .{ "bi.it", {} }, + .{ "biella.it", {} }, + .{ "bl.it", {} }, + .{ "bn.it", {} }, + .{ "bo.it", {} }, + .{ "bologna.it", {} }, + .{ "bolzano.it", {} }, + .{ "bolzano-altoadige.it", {} }, + .{ "bozen.it", {} }, + .{ "bozen-sudtirol.it", {} }, + .{ "bozen-südtirol.it", {} }, + .{ "bozen-suedtirol.it", {} }, + .{ "br.it", {} }, + .{ "brescia.it", {} }, + .{ "brindisi.it", {} }, + .{ "bs.it", {} }, + .{ "bt.it", {} }, + .{ "bulsan.it", {} }, + .{ "bulsan-sudtirol.it", {} }, + .{ "bulsan-südtirol.it", {} }, + .{ "bulsan-suedtirol.it", {} }, + .{ "bz.it", {} }, + .{ "ca.it", {} }, + .{ "cagliari.it", {} }, + .{ "caltanissetta.it", {} }, + .{ "campidano-medio.it", {} }, + .{ "campidanomedio.it", {} }, + .{ "campobasso.it", {} }, + .{ "carbonia-iglesias.it", {} }, + .{ "carboniaiglesias.it", {} }, + .{ "carrara-massa.it", {} }, + .{ "carraramassa.it", {} }, + .{ "caserta.it", {} }, + .{ "catania.it", {} }, + .{ "catanzaro.it", {} }, + .{ "cb.it", {} }, + .{ "ce.it", {} }, + .{ "cesena-forli.it", {} }, + .{ "cesena-forlì.it", {} }, + .{ "cesenaforli.it", {} }, + .{ "cesenaforlì.it", {} }, + .{ "ch.it", {} }, + .{ "chieti.it", {} }, + .{ "ci.it", {} }, + .{ "cl.it", {} }, + .{ "cn.it", {} }, + .{ "co.it", {} }, + .{ "como.it", {} }, + .{ "cosenza.it", {} }, + .{ "cr.it", {} }, + .{ "cremona.it", {} }, + .{ "crotone.it", {} }, + .{ "cs.it", {} }, + .{ "ct.it", {} }, + .{ "cuneo.it", {} }, + .{ "cz.it", {} }, + .{ "dell-ogliastra.it", {} }, + .{ "dellogliastra.it", {} }, + .{ "en.it", {} }, + .{ "enna.it", {} }, + .{ "fc.it", {} }, + .{ "fe.it", {} }, + .{ "fermo.it", {} }, + .{ "ferrara.it", {} }, + .{ "fg.it", {} }, + .{ "fi.it", {} }, + .{ "firenze.it", {} }, + .{ "florence.it", {} }, + .{ "fm.it", {} }, + .{ "foggia.it", {} }, + .{ "forli-cesena.it", {} }, + .{ "forlì-cesena.it", {} }, + .{ "forlicesena.it", {} }, + .{ "forlìcesena.it", {} }, + .{ "fr.it", {} }, + .{ "frosinone.it", {} }, + .{ "ge.it", {} }, + .{ "genoa.it", {} }, + .{ "genova.it", {} }, + .{ "go.it", {} }, + .{ "gorizia.it", {} }, + .{ "gr.it", {} }, + .{ "grosseto.it", {} }, + .{ "iglesias-carbonia.it", {} }, + .{ "iglesiascarbonia.it", {} }, + .{ "im.it", {} }, + .{ "imperia.it", {} }, + .{ "is.it", {} }, + .{ "isernia.it", {} }, + .{ "kr.it", {} }, + .{ "la-spezia.it", {} }, + .{ "laquila.it", {} }, + .{ "laspezia.it", {} }, + .{ "latina.it", {} }, + .{ "lc.it", {} }, + .{ "le.it", {} }, + .{ "lecce.it", {} }, + .{ "lecco.it", {} }, + .{ "li.it", {} }, + .{ "livorno.it", {} }, + .{ "lo.it", {} }, + .{ "lodi.it", {} }, + .{ "lt.it", {} }, + .{ "lu.it", {} }, + .{ "lucca.it", {} }, + .{ "macerata.it", {} }, + .{ "mantova.it", {} }, + .{ "massa-carrara.it", {} }, + .{ "massacarrara.it", {} }, + .{ "matera.it", {} }, + .{ "mb.it", {} }, + .{ "mc.it", {} }, + .{ "me.it", {} }, + .{ "medio-campidano.it", {} }, + .{ "mediocampidano.it", {} }, + .{ "messina.it", {} }, + .{ "mi.it", {} }, + .{ "milan.it", {} }, + .{ "milano.it", {} }, + .{ "mn.it", {} }, + .{ "mo.it", {} }, + .{ "modena.it", {} }, + .{ "monza.it", {} }, + .{ "monza-brianza.it", {} }, + .{ "monza-e-della-brianza.it", {} }, + .{ "monzabrianza.it", {} }, + .{ "monzaebrianza.it", {} }, + .{ "monzaedellabrianza.it", {} }, + .{ "ms.it", {} }, + .{ "mt.it", {} }, + .{ "na.it", {} }, + .{ "naples.it", {} }, + .{ "napoli.it", {} }, + .{ "no.it", {} }, + .{ "novara.it", {} }, + .{ "nu.it", {} }, + .{ "nuoro.it", {} }, + .{ "og.it", {} }, + .{ "ogliastra.it", {} }, + .{ "olbia-tempio.it", {} }, + .{ "olbiatempio.it", {} }, + .{ "or.it", {} }, + .{ "oristano.it", {} }, + .{ "ot.it", {} }, + .{ "pa.it", {} }, + .{ "padova.it", {} }, + .{ "padua.it", {} }, + .{ "palermo.it", {} }, + .{ "parma.it", {} }, + .{ "pavia.it", {} }, + .{ "pc.it", {} }, + .{ "pd.it", {} }, + .{ "pe.it", {} }, + .{ "perugia.it", {} }, + .{ "pesaro-urbino.it", {} }, + .{ "pesarourbino.it", {} }, + .{ "pescara.it", {} }, + .{ "pg.it", {} }, + .{ "pi.it", {} }, + .{ "piacenza.it", {} }, + .{ "pisa.it", {} }, + .{ "pistoia.it", {} }, + .{ "pn.it", {} }, + .{ "po.it", {} }, + .{ "pordenone.it", {} }, + .{ "potenza.it", {} }, + .{ "pr.it", {} }, + .{ "prato.it", {} }, + .{ "pt.it", {} }, + .{ "pu.it", {} }, + .{ "pv.it", {} }, + .{ "pz.it", {} }, + .{ "ra.it", {} }, + .{ "ragusa.it", {} }, + .{ "ravenna.it", {} }, + .{ "rc.it", {} }, + .{ "re.it", {} }, + .{ "reggio-calabria.it", {} }, + .{ "reggio-emilia.it", {} }, + .{ "reggiocalabria.it", {} }, + .{ "reggioemilia.it", {} }, + .{ "rg.it", {} }, + .{ "ri.it", {} }, + .{ "rieti.it", {} }, + .{ "rimini.it", {} }, + .{ "rm.it", {} }, + .{ "rn.it", {} }, + .{ "ro.it", {} }, + .{ "roma.it", {} }, + .{ "rome.it", {} }, + .{ "rovigo.it", {} }, + .{ "sa.it", {} }, + .{ "salerno.it", {} }, + .{ "sassari.it", {} }, + .{ "savona.it", {} }, + .{ "si.it", {} }, + .{ "siena.it", {} }, + .{ "siracusa.it", {} }, + .{ "so.it", {} }, + .{ "sondrio.it", {} }, + .{ "sp.it", {} }, + .{ "sr.it", {} }, + .{ "ss.it", {} }, + .{ "südtirol.it", {} }, + .{ "suedtirol.it", {} }, + .{ "sv.it", {} }, + .{ "ta.it", {} }, + .{ "taranto.it", {} }, + .{ "te.it", {} }, + .{ "tempio-olbia.it", {} }, + .{ "tempioolbia.it", {} }, + .{ "teramo.it", {} }, + .{ "terni.it", {} }, + .{ "tn.it", {} }, + .{ "to.it", {} }, + .{ "torino.it", {} }, + .{ "tp.it", {} }, + .{ "tr.it", {} }, + .{ "trani-andria-barletta.it", {} }, + .{ "trani-barletta-andria.it", {} }, + .{ "traniandriabarletta.it", {} }, + .{ "tranibarlettaandria.it", {} }, + .{ "trapani.it", {} }, + .{ "trento.it", {} }, + .{ "treviso.it", {} }, + .{ "trieste.it", {} }, + .{ "ts.it", {} }, + .{ "turin.it", {} }, + .{ "tv.it", {} }, + .{ "ud.it", {} }, + .{ "udine.it", {} }, + .{ "urbino-pesaro.it", {} }, + .{ "urbinopesaro.it", {} }, + .{ "va.it", {} }, + .{ "varese.it", {} }, + .{ "vb.it", {} }, + .{ "vc.it", {} }, + .{ "ve.it", {} }, + .{ "venezia.it", {} }, + .{ "venice.it", {} }, + .{ "verbania.it", {} }, + .{ "vercelli.it", {} }, + .{ "verona.it", {} }, + .{ "vi.it", {} }, + .{ "vibo-valentia.it", {} }, + .{ "vibovalentia.it", {} }, + .{ "vicenza.it", {} }, + .{ "viterbo.it", {} }, + .{ "vr.it", {} }, + .{ "vs.it", {} }, + .{ "vt.it", {} }, + .{ "vv.it", {} }, + .{ "je", {} }, + .{ "co.je", {} }, + .{ "net.je", {} }, + .{ "org.je", {} }, + .{ "*.jm", {} }, + .{ "jo", {} }, + .{ "agri.jo", {} }, + .{ "ai.jo", {} }, + .{ "com.jo", {} }, + .{ "edu.jo", {} }, + .{ "eng.jo", {} }, + .{ "fm.jo", {} }, + .{ "gov.jo", {} }, + .{ "mil.jo", {} }, + .{ "net.jo", {} }, + .{ "org.jo", {} }, + .{ "per.jo", {} }, + .{ "phd.jo", {} }, + .{ "sch.jo", {} }, + .{ "tv.jo", {} }, + .{ "jobs", {} }, + .{ "jp", {} }, + .{ "ac.jp", {} }, + .{ "ad.jp", {} }, + .{ "co.jp", {} }, + .{ "ed.jp", {} }, + .{ "go.jp", {} }, + .{ "gr.jp", {} }, + .{ "lg.jp", {} }, + .{ "ne.jp", {} }, + .{ "or.jp", {} }, + .{ "aichi.jp", {} }, + .{ "akita.jp", {} }, + .{ "aomori.jp", {} }, + .{ "chiba.jp", {} }, + .{ "ehime.jp", {} }, + .{ "fukui.jp", {} }, + .{ "fukuoka.jp", {} }, + .{ "fukushima.jp", {} }, + .{ "gifu.jp", {} }, + .{ "gunma.jp", {} }, + .{ "hiroshima.jp", {} }, + .{ "hokkaido.jp", {} }, + .{ "hyogo.jp", {} }, + .{ "ibaraki.jp", {} }, + .{ "ishikawa.jp", {} }, + .{ "iwate.jp", {} }, + .{ "kagawa.jp", {} }, + .{ "kagoshima.jp", {} }, + .{ "kanagawa.jp", {} }, + .{ "kochi.jp", {} }, + .{ "kumamoto.jp", {} }, + .{ "kyoto.jp", {} }, + .{ "mie.jp", {} }, + .{ "miyagi.jp", {} }, + .{ "miyazaki.jp", {} }, + .{ "nagano.jp", {} }, + .{ "nagasaki.jp", {} }, + .{ "nara.jp", {} }, + .{ "niigata.jp", {} }, + .{ "oita.jp", {} }, + .{ "okayama.jp", {} }, + .{ "okinawa.jp", {} }, + .{ "osaka.jp", {} }, + .{ "saga.jp", {} }, + .{ "saitama.jp", {} }, + .{ "shiga.jp", {} }, + .{ "shimane.jp", {} }, + .{ "shizuoka.jp", {} }, + .{ "tochigi.jp", {} }, + .{ "tokushima.jp", {} }, + .{ "tokyo.jp", {} }, + .{ "tottori.jp", {} }, + .{ "toyama.jp", {} }, + .{ "wakayama.jp", {} }, + .{ "yamagata.jp", {} }, + .{ "yamaguchi.jp", {} }, + .{ "yamanashi.jp", {} }, + .{ "三重.jp", {} }, + .{ "京都.jp", {} }, + .{ "佐賀.jp", {} }, + .{ "兵庫.jp", {} }, + .{ "北海道.jp", {} }, + .{ "千葉.jp", {} }, + .{ "和歌山.jp", {} }, + .{ "埼玉.jp", {} }, + .{ "大分.jp", {} }, + .{ "大阪.jp", {} }, + .{ "奈良.jp", {} }, + .{ "宮城.jp", {} }, + .{ "宮崎.jp", {} }, + .{ "富山.jp", {} }, + .{ "山口.jp", {} }, + .{ "山形.jp", {} }, + .{ "山梨.jp", {} }, + .{ "岐阜.jp", {} }, + .{ "岡山.jp", {} }, + .{ "岩手.jp", {} }, + .{ "島根.jp", {} }, + .{ "広島.jp", {} }, + .{ "徳島.jp", {} }, + .{ "愛媛.jp", {} }, + .{ "愛知.jp", {} }, + .{ "新潟.jp", {} }, + .{ "東京.jp", {} }, + .{ "栃木.jp", {} }, + .{ "沖縄.jp", {} }, + .{ "滋賀.jp", {} }, + .{ "熊本.jp", {} }, + .{ "石川.jp", {} }, + .{ "神奈川.jp", {} }, + .{ "福井.jp", {} }, + .{ "福岡.jp", {} }, + .{ "福島.jp", {} }, + .{ "秋田.jp", {} }, + .{ "群馬.jp", {} }, + .{ "茨城.jp", {} }, + .{ "長崎.jp", {} }, + .{ "長野.jp", {} }, + .{ "青森.jp", {} }, + .{ "静岡.jp", {} }, + .{ "香川.jp", {} }, + .{ "高知.jp", {} }, + .{ "鳥取.jp", {} }, + .{ "鹿児島.jp", {} }, + .{ "*.kawasaki.jp", {} }, + .{ "!city.kawasaki.jp", {} }, + .{ "*.kitakyushu.jp", {} }, + .{ "!city.kitakyushu.jp", {} }, + .{ "*.kobe.jp", {} }, + .{ "!city.kobe.jp", {} }, + .{ "*.nagoya.jp", {} }, + .{ "!city.nagoya.jp", {} }, + .{ "*.sapporo.jp", {} }, + .{ "!city.sapporo.jp", {} }, + .{ "*.sendai.jp", {} }, + .{ "!city.sendai.jp", {} }, + .{ "*.yokohama.jp", {} }, + .{ "!city.yokohama.jp", {} }, + .{ "aisai.aichi.jp", {} }, + .{ "ama.aichi.jp", {} }, + .{ "anjo.aichi.jp", {} }, + .{ "asuke.aichi.jp", {} }, + .{ "chiryu.aichi.jp", {} }, + .{ "chita.aichi.jp", {} }, + .{ "fuso.aichi.jp", {} }, + .{ "gamagori.aichi.jp", {} }, + .{ "handa.aichi.jp", {} }, + .{ "hazu.aichi.jp", {} }, + .{ "hekinan.aichi.jp", {} }, + .{ "higashiura.aichi.jp", {} }, + .{ "ichinomiya.aichi.jp", {} }, + .{ "inazawa.aichi.jp", {} }, + .{ "inuyama.aichi.jp", {} }, + .{ "isshiki.aichi.jp", {} }, + .{ "iwakura.aichi.jp", {} }, + .{ "kanie.aichi.jp", {} }, + .{ "kariya.aichi.jp", {} }, + .{ "kasugai.aichi.jp", {} }, + .{ "kira.aichi.jp", {} }, + .{ "kiyosu.aichi.jp", {} }, + .{ "komaki.aichi.jp", {} }, + .{ "konan.aichi.jp", {} }, + .{ "kota.aichi.jp", {} }, + .{ "mihama.aichi.jp", {} }, + .{ "miyoshi.aichi.jp", {} }, + .{ "nishio.aichi.jp", {} }, + .{ "nisshin.aichi.jp", {} }, + .{ "obu.aichi.jp", {} }, + .{ "oguchi.aichi.jp", {} }, + .{ "oharu.aichi.jp", {} }, + .{ "okazaki.aichi.jp", {} }, + .{ "owariasahi.aichi.jp", {} }, + .{ "seto.aichi.jp", {} }, + .{ "shikatsu.aichi.jp", {} }, + .{ "shinshiro.aichi.jp", {} }, + .{ "shitara.aichi.jp", {} }, + .{ "tahara.aichi.jp", {} }, + .{ "takahama.aichi.jp", {} }, + .{ "tobishima.aichi.jp", {} }, + .{ "toei.aichi.jp", {} }, + .{ "togo.aichi.jp", {} }, + .{ "tokai.aichi.jp", {} }, + .{ "tokoname.aichi.jp", {} }, + .{ "toyoake.aichi.jp", {} }, + .{ "toyohashi.aichi.jp", {} }, + .{ "toyokawa.aichi.jp", {} }, + .{ "toyone.aichi.jp", {} }, + .{ "toyota.aichi.jp", {} }, + .{ "tsushima.aichi.jp", {} }, + .{ "yatomi.aichi.jp", {} }, + .{ "akita.akita.jp", {} }, + .{ "daisen.akita.jp", {} }, + .{ "fujisato.akita.jp", {} }, + .{ "gojome.akita.jp", {} }, + .{ "hachirogata.akita.jp", {} }, + .{ "happou.akita.jp", {} }, + .{ "higashinaruse.akita.jp", {} }, + .{ "honjo.akita.jp", {} }, + .{ "honjyo.akita.jp", {} }, + .{ "ikawa.akita.jp", {} }, + .{ "kamikoani.akita.jp", {} }, + .{ "kamioka.akita.jp", {} }, + .{ "katagami.akita.jp", {} }, + .{ "kazuno.akita.jp", {} }, + .{ "kitaakita.akita.jp", {} }, + .{ "kosaka.akita.jp", {} }, + .{ "kyowa.akita.jp", {} }, + .{ "misato.akita.jp", {} }, + .{ "mitane.akita.jp", {} }, + .{ "moriyoshi.akita.jp", {} }, + .{ "nikaho.akita.jp", {} }, + .{ "noshiro.akita.jp", {} }, + .{ "odate.akita.jp", {} }, + .{ "oga.akita.jp", {} }, + .{ "ogata.akita.jp", {} }, + .{ "semboku.akita.jp", {} }, + .{ "yokote.akita.jp", {} }, + .{ "yurihonjo.akita.jp", {} }, + .{ "aomori.aomori.jp", {} }, + .{ "gonohe.aomori.jp", {} }, + .{ "hachinohe.aomori.jp", {} }, + .{ "hashikami.aomori.jp", {} }, + .{ "hiranai.aomori.jp", {} }, + .{ "hirosaki.aomori.jp", {} }, + .{ "itayanagi.aomori.jp", {} }, + .{ "kuroishi.aomori.jp", {} }, + .{ "misawa.aomori.jp", {} }, + .{ "mutsu.aomori.jp", {} }, + .{ "nakadomari.aomori.jp", {} }, + .{ "noheji.aomori.jp", {} }, + .{ "oirase.aomori.jp", {} }, + .{ "owani.aomori.jp", {} }, + .{ "rokunohe.aomori.jp", {} }, + .{ "sannohe.aomori.jp", {} }, + .{ "shichinohe.aomori.jp", {} }, + .{ "shingo.aomori.jp", {} }, + .{ "takko.aomori.jp", {} }, + .{ "towada.aomori.jp", {} }, + .{ "tsugaru.aomori.jp", {} }, + .{ "tsuruta.aomori.jp", {} }, + .{ "abiko.chiba.jp", {} }, + .{ "asahi.chiba.jp", {} }, + .{ "chonan.chiba.jp", {} }, + .{ "chosei.chiba.jp", {} }, + .{ "choshi.chiba.jp", {} }, + .{ "chuo.chiba.jp", {} }, + .{ "funabashi.chiba.jp", {} }, + .{ "futtsu.chiba.jp", {} }, + .{ "hanamigawa.chiba.jp", {} }, + .{ "ichihara.chiba.jp", {} }, + .{ "ichikawa.chiba.jp", {} }, + .{ "ichinomiya.chiba.jp", {} }, + .{ "inzai.chiba.jp", {} }, + .{ "isumi.chiba.jp", {} }, + .{ "kamagaya.chiba.jp", {} }, + .{ "kamogawa.chiba.jp", {} }, + .{ "kashiwa.chiba.jp", {} }, + .{ "katori.chiba.jp", {} }, + .{ "katsuura.chiba.jp", {} }, + .{ "kimitsu.chiba.jp", {} }, + .{ "kisarazu.chiba.jp", {} }, + .{ "kozaki.chiba.jp", {} }, + .{ "kujukuri.chiba.jp", {} }, + .{ "kyonan.chiba.jp", {} }, + .{ "matsudo.chiba.jp", {} }, + .{ "midori.chiba.jp", {} }, + .{ "mihama.chiba.jp", {} }, + .{ "minamiboso.chiba.jp", {} }, + .{ "mobara.chiba.jp", {} }, + .{ "mutsuzawa.chiba.jp", {} }, + .{ "nagara.chiba.jp", {} }, + .{ "nagareyama.chiba.jp", {} }, + .{ "narashino.chiba.jp", {} }, + .{ "narita.chiba.jp", {} }, + .{ "noda.chiba.jp", {} }, + .{ "oamishirasato.chiba.jp", {} }, + .{ "omigawa.chiba.jp", {} }, + .{ "onjuku.chiba.jp", {} }, + .{ "otaki.chiba.jp", {} }, + .{ "sakae.chiba.jp", {} }, + .{ "sakura.chiba.jp", {} }, + .{ "shimofusa.chiba.jp", {} }, + .{ "shirako.chiba.jp", {} }, + .{ "shiroi.chiba.jp", {} }, + .{ "shisui.chiba.jp", {} }, + .{ "sodegaura.chiba.jp", {} }, + .{ "sosa.chiba.jp", {} }, + .{ "tako.chiba.jp", {} }, + .{ "tateyama.chiba.jp", {} }, + .{ "togane.chiba.jp", {} }, + .{ "tohnosho.chiba.jp", {} }, + .{ "tomisato.chiba.jp", {} }, + .{ "urayasu.chiba.jp", {} }, + .{ "yachimata.chiba.jp", {} }, + .{ "yachiyo.chiba.jp", {} }, + .{ "yokaichiba.chiba.jp", {} }, + .{ "yokoshibahikari.chiba.jp", {} }, + .{ "yotsukaido.chiba.jp", {} }, + .{ "ainan.ehime.jp", {} }, + .{ "honai.ehime.jp", {} }, + .{ "ikata.ehime.jp", {} }, + .{ "imabari.ehime.jp", {} }, + .{ "iyo.ehime.jp", {} }, + .{ "kamijima.ehime.jp", {} }, + .{ "kihoku.ehime.jp", {} }, + .{ "kumakogen.ehime.jp", {} }, + .{ "masaki.ehime.jp", {} }, + .{ "matsuno.ehime.jp", {} }, + .{ "matsuyama.ehime.jp", {} }, + .{ "namikata.ehime.jp", {} }, + .{ "niihama.ehime.jp", {} }, + .{ "ozu.ehime.jp", {} }, + .{ "saijo.ehime.jp", {} }, + .{ "seiyo.ehime.jp", {} }, + .{ "shikokuchuo.ehime.jp", {} }, + .{ "tobe.ehime.jp", {} }, + .{ "toon.ehime.jp", {} }, + .{ "uchiko.ehime.jp", {} }, + .{ "uwajima.ehime.jp", {} }, + .{ "yawatahama.ehime.jp", {} }, + .{ "echizen.fukui.jp", {} }, + .{ "eiheiji.fukui.jp", {} }, + .{ "fukui.fukui.jp", {} }, + .{ "ikeda.fukui.jp", {} }, + .{ "katsuyama.fukui.jp", {} }, + .{ "mihama.fukui.jp", {} }, + .{ "minamiechizen.fukui.jp", {} }, + .{ "obama.fukui.jp", {} }, + .{ "ohi.fukui.jp", {} }, + .{ "ono.fukui.jp", {} }, + .{ "sabae.fukui.jp", {} }, + .{ "sakai.fukui.jp", {} }, + .{ "takahama.fukui.jp", {} }, + .{ "tsuruga.fukui.jp", {} }, + .{ "wakasa.fukui.jp", {} }, + .{ "ashiya.fukuoka.jp", {} }, + .{ "buzen.fukuoka.jp", {} }, + .{ "chikugo.fukuoka.jp", {} }, + .{ "chikuho.fukuoka.jp", {} }, + .{ "chikujo.fukuoka.jp", {} }, + .{ "chikushino.fukuoka.jp", {} }, + .{ "chikuzen.fukuoka.jp", {} }, + .{ "chuo.fukuoka.jp", {} }, + .{ "dazaifu.fukuoka.jp", {} }, + .{ "fukuchi.fukuoka.jp", {} }, + .{ "hakata.fukuoka.jp", {} }, + .{ "higashi.fukuoka.jp", {} }, + .{ "hirokawa.fukuoka.jp", {} }, + .{ "hisayama.fukuoka.jp", {} }, + .{ "iizuka.fukuoka.jp", {} }, + .{ "inatsuki.fukuoka.jp", {} }, + .{ "kaho.fukuoka.jp", {} }, + .{ "kasuga.fukuoka.jp", {} }, + .{ "kasuya.fukuoka.jp", {} }, + .{ "kawara.fukuoka.jp", {} }, + .{ "keisen.fukuoka.jp", {} }, + .{ "koga.fukuoka.jp", {} }, + .{ "kurate.fukuoka.jp", {} }, + .{ "kurogi.fukuoka.jp", {} }, + .{ "kurume.fukuoka.jp", {} }, + .{ "minami.fukuoka.jp", {} }, + .{ "miyako.fukuoka.jp", {} }, + .{ "miyama.fukuoka.jp", {} }, + .{ "miyawaka.fukuoka.jp", {} }, + .{ "mizumaki.fukuoka.jp", {} }, + .{ "munakata.fukuoka.jp", {} }, + .{ "nakagawa.fukuoka.jp", {} }, + .{ "nakama.fukuoka.jp", {} }, + .{ "nishi.fukuoka.jp", {} }, + .{ "nogata.fukuoka.jp", {} }, + .{ "ogori.fukuoka.jp", {} }, + .{ "okagaki.fukuoka.jp", {} }, + .{ "okawa.fukuoka.jp", {} }, + .{ "oki.fukuoka.jp", {} }, + .{ "omuta.fukuoka.jp", {} }, + .{ "onga.fukuoka.jp", {} }, + .{ "onojo.fukuoka.jp", {} }, + .{ "oto.fukuoka.jp", {} }, + .{ "saigawa.fukuoka.jp", {} }, + .{ "sasaguri.fukuoka.jp", {} }, + .{ "shingu.fukuoka.jp", {} }, + .{ "shinyoshitomi.fukuoka.jp", {} }, + .{ "shonai.fukuoka.jp", {} }, + .{ "soeda.fukuoka.jp", {} }, + .{ "sue.fukuoka.jp", {} }, + .{ "tachiarai.fukuoka.jp", {} }, + .{ "tagawa.fukuoka.jp", {} }, + .{ "takata.fukuoka.jp", {} }, + .{ "toho.fukuoka.jp", {} }, + .{ "toyotsu.fukuoka.jp", {} }, + .{ "tsuiki.fukuoka.jp", {} }, + .{ "ukiha.fukuoka.jp", {} }, + .{ "umi.fukuoka.jp", {} }, + .{ "usui.fukuoka.jp", {} }, + .{ "yamada.fukuoka.jp", {} }, + .{ "yame.fukuoka.jp", {} }, + .{ "yanagawa.fukuoka.jp", {} }, + .{ "yukuhashi.fukuoka.jp", {} }, + .{ "aizubange.fukushima.jp", {} }, + .{ "aizumisato.fukushima.jp", {} }, + .{ "aizuwakamatsu.fukushima.jp", {} }, + .{ "asakawa.fukushima.jp", {} }, + .{ "bandai.fukushima.jp", {} }, + .{ "date.fukushima.jp", {} }, + .{ "fukushima.fukushima.jp", {} }, + .{ "furudono.fukushima.jp", {} }, + .{ "futaba.fukushima.jp", {} }, + .{ "hanawa.fukushima.jp", {} }, + .{ "higashi.fukushima.jp", {} }, + .{ "hirata.fukushima.jp", {} }, + .{ "hirono.fukushima.jp", {} }, + .{ "iitate.fukushima.jp", {} }, + .{ "inawashiro.fukushima.jp", {} }, + .{ "ishikawa.fukushima.jp", {} }, + .{ "iwaki.fukushima.jp", {} }, + .{ "izumizaki.fukushima.jp", {} }, + .{ "kagamiishi.fukushima.jp", {} }, + .{ "kaneyama.fukushima.jp", {} }, + .{ "kawamata.fukushima.jp", {} }, + .{ "kitakata.fukushima.jp", {} }, + .{ "kitashiobara.fukushima.jp", {} }, + .{ "koori.fukushima.jp", {} }, + .{ "koriyama.fukushima.jp", {} }, + .{ "kunimi.fukushima.jp", {} }, + .{ "miharu.fukushima.jp", {} }, + .{ "mishima.fukushima.jp", {} }, + .{ "namie.fukushima.jp", {} }, + .{ "nango.fukushima.jp", {} }, + .{ "nishiaizu.fukushima.jp", {} }, + .{ "nishigo.fukushima.jp", {} }, + .{ "okuma.fukushima.jp", {} }, + .{ "omotego.fukushima.jp", {} }, + .{ "ono.fukushima.jp", {} }, + .{ "otama.fukushima.jp", {} }, + .{ "samegawa.fukushima.jp", {} }, + .{ "shimogo.fukushima.jp", {} }, + .{ "shirakawa.fukushima.jp", {} }, + .{ "showa.fukushima.jp", {} }, + .{ "soma.fukushima.jp", {} }, + .{ "sukagawa.fukushima.jp", {} }, + .{ "taishin.fukushima.jp", {} }, + .{ "tamakawa.fukushima.jp", {} }, + .{ "tanagura.fukushima.jp", {} }, + .{ "tenei.fukushima.jp", {} }, + .{ "yabuki.fukushima.jp", {} }, + .{ "yamato.fukushima.jp", {} }, + .{ "yamatsuri.fukushima.jp", {} }, + .{ "yanaizu.fukushima.jp", {} }, + .{ "yugawa.fukushima.jp", {} }, + .{ "anpachi.gifu.jp", {} }, + .{ "ena.gifu.jp", {} }, + .{ "gifu.gifu.jp", {} }, + .{ "ginan.gifu.jp", {} }, + .{ "godo.gifu.jp", {} }, + .{ "gujo.gifu.jp", {} }, + .{ "hashima.gifu.jp", {} }, + .{ "hichiso.gifu.jp", {} }, + .{ "hida.gifu.jp", {} }, + .{ "higashishirakawa.gifu.jp", {} }, + .{ "ibigawa.gifu.jp", {} }, + .{ "ikeda.gifu.jp", {} }, + .{ "kakamigahara.gifu.jp", {} }, + .{ "kani.gifu.jp", {} }, + .{ "kasahara.gifu.jp", {} }, + .{ "kasamatsu.gifu.jp", {} }, + .{ "kawaue.gifu.jp", {} }, + .{ "kitagata.gifu.jp", {} }, + .{ "mino.gifu.jp", {} }, + .{ "minokamo.gifu.jp", {} }, + .{ "mitake.gifu.jp", {} }, + .{ "mizunami.gifu.jp", {} }, + .{ "motosu.gifu.jp", {} }, + .{ "nakatsugawa.gifu.jp", {} }, + .{ "ogaki.gifu.jp", {} }, + .{ "sakahogi.gifu.jp", {} }, + .{ "seki.gifu.jp", {} }, + .{ "sekigahara.gifu.jp", {} }, + .{ "shirakawa.gifu.jp", {} }, + .{ "tajimi.gifu.jp", {} }, + .{ "takayama.gifu.jp", {} }, + .{ "tarui.gifu.jp", {} }, + .{ "toki.gifu.jp", {} }, + .{ "tomika.gifu.jp", {} }, + .{ "wanouchi.gifu.jp", {} }, + .{ "yamagata.gifu.jp", {} }, + .{ "yaotsu.gifu.jp", {} }, + .{ "yoro.gifu.jp", {} }, + .{ "annaka.gunma.jp", {} }, + .{ "chiyoda.gunma.jp", {} }, + .{ "fujioka.gunma.jp", {} }, + .{ "higashiagatsuma.gunma.jp", {} }, + .{ "isesaki.gunma.jp", {} }, + .{ "itakura.gunma.jp", {} }, + .{ "kanna.gunma.jp", {} }, + .{ "kanra.gunma.jp", {} }, + .{ "katashina.gunma.jp", {} }, + .{ "kawaba.gunma.jp", {} }, + .{ "kiryu.gunma.jp", {} }, + .{ "kusatsu.gunma.jp", {} }, + .{ "maebashi.gunma.jp", {} }, + .{ "meiwa.gunma.jp", {} }, + .{ "midori.gunma.jp", {} }, + .{ "minakami.gunma.jp", {} }, + .{ "naganohara.gunma.jp", {} }, + .{ "nakanojo.gunma.jp", {} }, + .{ "nanmoku.gunma.jp", {} }, + .{ "numata.gunma.jp", {} }, + .{ "oizumi.gunma.jp", {} }, + .{ "ora.gunma.jp", {} }, + .{ "ota.gunma.jp", {} }, + .{ "shibukawa.gunma.jp", {} }, + .{ "shimonita.gunma.jp", {} }, + .{ "shinto.gunma.jp", {} }, + .{ "showa.gunma.jp", {} }, + .{ "takasaki.gunma.jp", {} }, + .{ "takayama.gunma.jp", {} }, + .{ "tamamura.gunma.jp", {} }, + .{ "tatebayashi.gunma.jp", {} }, + .{ "tomioka.gunma.jp", {} }, + .{ "tsukiyono.gunma.jp", {} }, + .{ "tsumagoi.gunma.jp", {} }, + .{ "ueno.gunma.jp", {} }, + .{ "yoshioka.gunma.jp", {} }, + .{ "asaminami.hiroshima.jp", {} }, + .{ "daiwa.hiroshima.jp", {} }, + .{ "etajima.hiroshima.jp", {} }, + .{ "fuchu.hiroshima.jp", {} }, + .{ "fukuyama.hiroshima.jp", {} }, + .{ "hatsukaichi.hiroshima.jp", {} }, + .{ "higashihiroshima.hiroshima.jp", {} }, + .{ "hongo.hiroshima.jp", {} }, + .{ "jinsekikogen.hiroshima.jp", {} }, + .{ "kaita.hiroshima.jp", {} }, + .{ "kui.hiroshima.jp", {} }, + .{ "kumano.hiroshima.jp", {} }, + .{ "kure.hiroshima.jp", {} }, + .{ "mihara.hiroshima.jp", {} }, + .{ "miyoshi.hiroshima.jp", {} }, + .{ "naka.hiroshima.jp", {} }, + .{ "onomichi.hiroshima.jp", {} }, + .{ "osakikamijima.hiroshima.jp", {} }, + .{ "otake.hiroshima.jp", {} }, + .{ "saka.hiroshima.jp", {} }, + .{ "sera.hiroshima.jp", {} }, + .{ "seranishi.hiroshima.jp", {} }, + .{ "shinichi.hiroshima.jp", {} }, + .{ "shobara.hiroshima.jp", {} }, + .{ "takehara.hiroshima.jp", {} }, + .{ "abashiri.hokkaido.jp", {} }, + .{ "abira.hokkaido.jp", {} }, + .{ "aibetsu.hokkaido.jp", {} }, + .{ "akabira.hokkaido.jp", {} }, + .{ "akkeshi.hokkaido.jp", {} }, + .{ "asahikawa.hokkaido.jp", {} }, + .{ "ashibetsu.hokkaido.jp", {} }, + .{ "ashoro.hokkaido.jp", {} }, + .{ "assabu.hokkaido.jp", {} }, + .{ "atsuma.hokkaido.jp", {} }, + .{ "bibai.hokkaido.jp", {} }, + .{ "biei.hokkaido.jp", {} }, + .{ "bifuka.hokkaido.jp", {} }, + .{ "bihoro.hokkaido.jp", {} }, + .{ "biratori.hokkaido.jp", {} }, + .{ "chippubetsu.hokkaido.jp", {} }, + .{ "chitose.hokkaido.jp", {} }, + .{ "date.hokkaido.jp", {} }, + .{ "ebetsu.hokkaido.jp", {} }, + .{ "embetsu.hokkaido.jp", {} }, + .{ "eniwa.hokkaido.jp", {} }, + .{ "erimo.hokkaido.jp", {} }, + .{ "esan.hokkaido.jp", {} }, + .{ "esashi.hokkaido.jp", {} }, + .{ "fukagawa.hokkaido.jp", {} }, + .{ "fukushima.hokkaido.jp", {} }, + .{ "furano.hokkaido.jp", {} }, + .{ "furubira.hokkaido.jp", {} }, + .{ "haboro.hokkaido.jp", {} }, + .{ "hakodate.hokkaido.jp", {} }, + .{ "hamatonbetsu.hokkaido.jp", {} }, + .{ "hidaka.hokkaido.jp", {} }, + .{ "higashikagura.hokkaido.jp", {} }, + .{ "higashikawa.hokkaido.jp", {} }, + .{ "hiroo.hokkaido.jp", {} }, + .{ "hokuryu.hokkaido.jp", {} }, + .{ "hokuto.hokkaido.jp", {} }, + .{ "honbetsu.hokkaido.jp", {} }, + .{ "horokanai.hokkaido.jp", {} }, + .{ "horonobe.hokkaido.jp", {} }, + .{ "ikeda.hokkaido.jp", {} }, + .{ "imakane.hokkaido.jp", {} }, + .{ "ishikari.hokkaido.jp", {} }, + .{ "iwamizawa.hokkaido.jp", {} }, + .{ "iwanai.hokkaido.jp", {} }, + .{ "kamifurano.hokkaido.jp", {} }, + .{ "kamikawa.hokkaido.jp", {} }, + .{ "kamishihoro.hokkaido.jp", {} }, + .{ "kamisunagawa.hokkaido.jp", {} }, + .{ "kamoenai.hokkaido.jp", {} }, + .{ "kayabe.hokkaido.jp", {} }, + .{ "kembuchi.hokkaido.jp", {} }, + .{ "kikonai.hokkaido.jp", {} }, + .{ "kimobetsu.hokkaido.jp", {} }, + .{ "kitahiroshima.hokkaido.jp", {} }, + .{ "kitami.hokkaido.jp", {} }, + .{ "kiyosato.hokkaido.jp", {} }, + .{ "koshimizu.hokkaido.jp", {} }, + .{ "kunneppu.hokkaido.jp", {} }, + .{ "kuriyama.hokkaido.jp", {} }, + .{ "kuromatsunai.hokkaido.jp", {} }, + .{ "kushiro.hokkaido.jp", {} }, + .{ "kutchan.hokkaido.jp", {} }, + .{ "kyowa.hokkaido.jp", {} }, + .{ "mashike.hokkaido.jp", {} }, + .{ "matsumae.hokkaido.jp", {} }, + .{ "mikasa.hokkaido.jp", {} }, + .{ "minamifurano.hokkaido.jp", {} }, + .{ "mombetsu.hokkaido.jp", {} }, + .{ "moseushi.hokkaido.jp", {} }, + .{ "mukawa.hokkaido.jp", {} }, + .{ "muroran.hokkaido.jp", {} }, + .{ "naie.hokkaido.jp", {} }, + .{ "nakagawa.hokkaido.jp", {} }, + .{ "nakasatsunai.hokkaido.jp", {} }, + .{ "nakatombetsu.hokkaido.jp", {} }, + .{ "nanae.hokkaido.jp", {} }, + .{ "nanporo.hokkaido.jp", {} }, + .{ "nayoro.hokkaido.jp", {} }, + .{ "nemuro.hokkaido.jp", {} }, + .{ "niikappu.hokkaido.jp", {} }, + .{ "niki.hokkaido.jp", {} }, + .{ "nishiokoppe.hokkaido.jp", {} }, + .{ "noboribetsu.hokkaido.jp", {} }, + .{ "numata.hokkaido.jp", {} }, + .{ "obihiro.hokkaido.jp", {} }, + .{ "obira.hokkaido.jp", {} }, + .{ "oketo.hokkaido.jp", {} }, + .{ "okoppe.hokkaido.jp", {} }, + .{ "otaru.hokkaido.jp", {} }, + .{ "otobe.hokkaido.jp", {} }, + .{ "otofuke.hokkaido.jp", {} }, + .{ "otoineppu.hokkaido.jp", {} }, + .{ "oumu.hokkaido.jp", {} }, + .{ "ozora.hokkaido.jp", {} }, + .{ "pippu.hokkaido.jp", {} }, + .{ "rankoshi.hokkaido.jp", {} }, + .{ "rebun.hokkaido.jp", {} }, + .{ "rikubetsu.hokkaido.jp", {} }, + .{ "rishiri.hokkaido.jp", {} }, + .{ "rishirifuji.hokkaido.jp", {} }, + .{ "saroma.hokkaido.jp", {} }, + .{ "sarufutsu.hokkaido.jp", {} }, + .{ "shakotan.hokkaido.jp", {} }, + .{ "shari.hokkaido.jp", {} }, + .{ "shibecha.hokkaido.jp", {} }, + .{ "shibetsu.hokkaido.jp", {} }, + .{ "shikabe.hokkaido.jp", {} }, + .{ "shikaoi.hokkaido.jp", {} }, + .{ "shimamaki.hokkaido.jp", {} }, + .{ "shimizu.hokkaido.jp", {} }, + .{ "shimokawa.hokkaido.jp", {} }, + .{ "shinshinotsu.hokkaido.jp", {} }, + .{ "shintoku.hokkaido.jp", {} }, + .{ "shiranuka.hokkaido.jp", {} }, + .{ "shiraoi.hokkaido.jp", {} }, + .{ "shiriuchi.hokkaido.jp", {} }, + .{ "sobetsu.hokkaido.jp", {} }, + .{ "sunagawa.hokkaido.jp", {} }, + .{ "taiki.hokkaido.jp", {} }, + .{ "takasu.hokkaido.jp", {} }, + .{ "takikawa.hokkaido.jp", {} }, + .{ "takinoue.hokkaido.jp", {} }, + .{ "teshikaga.hokkaido.jp", {} }, + .{ "tobetsu.hokkaido.jp", {} }, + .{ "tohma.hokkaido.jp", {} }, + .{ "tomakomai.hokkaido.jp", {} }, + .{ "tomari.hokkaido.jp", {} }, + .{ "toya.hokkaido.jp", {} }, + .{ "toyako.hokkaido.jp", {} }, + .{ "toyotomi.hokkaido.jp", {} }, + .{ "toyoura.hokkaido.jp", {} }, + .{ "tsubetsu.hokkaido.jp", {} }, + .{ "tsukigata.hokkaido.jp", {} }, + .{ "urakawa.hokkaido.jp", {} }, + .{ "urausu.hokkaido.jp", {} }, + .{ "uryu.hokkaido.jp", {} }, + .{ "utashinai.hokkaido.jp", {} }, + .{ "wakkanai.hokkaido.jp", {} }, + .{ "wassamu.hokkaido.jp", {} }, + .{ "yakumo.hokkaido.jp", {} }, + .{ "yoichi.hokkaido.jp", {} }, + .{ "aioi.hyogo.jp", {} }, + .{ "akashi.hyogo.jp", {} }, + .{ "ako.hyogo.jp", {} }, + .{ "amagasaki.hyogo.jp", {} }, + .{ "aogaki.hyogo.jp", {} }, + .{ "asago.hyogo.jp", {} }, + .{ "ashiya.hyogo.jp", {} }, + .{ "awaji.hyogo.jp", {} }, + .{ "fukusaki.hyogo.jp", {} }, + .{ "goshiki.hyogo.jp", {} }, + .{ "harima.hyogo.jp", {} }, + .{ "himeji.hyogo.jp", {} }, + .{ "ichikawa.hyogo.jp", {} }, + .{ "inagawa.hyogo.jp", {} }, + .{ "itami.hyogo.jp", {} }, + .{ "kakogawa.hyogo.jp", {} }, + .{ "kamigori.hyogo.jp", {} }, + .{ "kamikawa.hyogo.jp", {} }, + .{ "kasai.hyogo.jp", {} }, + .{ "kasuga.hyogo.jp", {} }, + .{ "kawanishi.hyogo.jp", {} }, + .{ "miki.hyogo.jp", {} }, + .{ "minamiawaji.hyogo.jp", {} }, + .{ "nishinomiya.hyogo.jp", {} }, + .{ "nishiwaki.hyogo.jp", {} }, + .{ "ono.hyogo.jp", {} }, + .{ "sanda.hyogo.jp", {} }, + .{ "sannan.hyogo.jp", {} }, + .{ "sasayama.hyogo.jp", {} }, + .{ "sayo.hyogo.jp", {} }, + .{ "shingu.hyogo.jp", {} }, + .{ "shinonsen.hyogo.jp", {} }, + .{ "shiso.hyogo.jp", {} }, + .{ "sumoto.hyogo.jp", {} }, + .{ "taishi.hyogo.jp", {} }, + .{ "taka.hyogo.jp", {} }, + .{ "takarazuka.hyogo.jp", {} }, + .{ "takasago.hyogo.jp", {} }, + .{ "takino.hyogo.jp", {} }, + .{ "tamba.hyogo.jp", {} }, + .{ "tatsuno.hyogo.jp", {} }, + .{ "toyooka.hyogo.jp", {} }, + .{ "yabu.hyogo.jp", {} }, + .{ "yashiro.hyogo.jp", {} }, + .{ "yoka.hyogo.jp", {} }, + .{ "yokawa.hyogo.jp", {} }, + .{ "ami.ibaraki.jp", {} }, + .{ "asahi.ibaraki.jp", {} }, + .{ "bando.ibaraki.jp", {} }, + .{ "chikusei.ibaraki.jp", {} }, + .{ "daigo.ibaraki.jp", {} }, + .{ "fujishiro.ibaraki.jp", {} }, + .{ "hitachi.ibaraki.jp", {} }, + .{ "hitachinaka.ibaraki.jp", {} }, + .{ "hitachiomiya.ibaraki.jp", {} }, + .{ "hitachiota.ibaraki.jp", {} }, + .{ "ibaraki.ibaraki.jp", {} }, + .{ "ina.ibaraki.jp", {} }, + .{ "inashiki.ibaraki.jp", {} }, + .{ "itako.ibaraki.jp", {} }, + .{ "iwama.ibaraki.jp", {} }, + .{ "joso.ibaraki.jp", {} }, + .{ "kamisu.ibaraki.jp", {} }, + .{ "kasama.ibaraki.jp", {} }, + .{ "kashima.ibaraki.jp", {} }, + .{ "kasumigaura.ibaraki.jp", {} }, + .{ "koga.ibaraki.jp", {} }, + .{ "miho.ibaraki.jp", {} }, + .{ "mito.ibaraki.jp", {} }, + .{ "moriya.ibaraki.jp", {} }, + .{ "naka.ibaraki.jp", {} }, + .{ "namegata.ibaraki.jp", {} }, + .{ "oarai.ibaraki.jp", {} }, + .{ "ogawa.ibaraki.jp", {} }, + .{ "omitama.ibaraki.jp", {} }, + .{ "ryugasaki.ibaraki.jp", {} }, + .{ "sakai.ibaraki.jp", {} }, + .{ "sakuragawa.ibaraki.jp", {} }, + .{ "shimodate.ibaraki.jp", {} }, + .{ "shimotsuma.ibaraki.jp", {} }, + .{ "shirosato.ibaraki.jp", {} }, + .{ "sowa.ibaraki.jp", {} }, + .{ "suifu.ibaraki.jp", {} }, + .{ "takahagi.ibaraki.jp", {} }, + .{ "tamatsukuri.ibaraki.jp", {} }, + .{ "tokai.ibaraki.jp", {} }, + .{ "tomobe.ibaraki.jp", {} }, + .{ "tone.ibaraki.jp", {} }, + .{ "toride.ibaraki.jp", {} }, + .{ "tsuchiura.ibaraki.jp", {} }, + .{ "tsukuba.ibaraki.jp", {} }, + .{ "uchihara.ibaraki.jp", {} }, + .{ "ushiku.ibaraki.jp", {} }, + .{ "yachiyo.ibaraki.jp", {} }, + .{ "yamagata.ibaraki.jp", {} }, + .{ "yawara.ibaraki.jp", {} }, + .{ "yuki.ibaraki.jp", {} }, + .{ "anamizu.ishikawa.jp", {} }, + .{ "hakui.ishikawa.jp", {} }, + .{ "hakusan.ishikawa.jp", {} }, + .{ "kaga.ishikawa.jp", {} }, + .{ "kahoku.ishikawa.jp", {} }, + .{ "kanazawa.ishikawa.jp", {} }, + .{ "kawakita.ishikawa.jp", {} }, + .{ "komatsu.ishikawa.jp", {} }, + .{ "nakanoto.ishikawa.jp", {} }, + .{ "nanao.ishikawa.jp", {} }, + .{ "nomi.ishikawa.jp", {} }, + .{ "nonoichi.ishikawa.jp", {} }, + .{ "noto.ishikawa.jp", {} }, + .{ "shika.ishikawa.jp", {} }, + .{ "suzu.ishikawa.jp", {} }, + .{ "tsubata.ishikawa.jp", {} }, + .{ "tsurugi.ishikawa.jp", {} }, + .{ "uchinada.ishikawa.jp", {} }, + .{ "wajima.ishikawa.jp", {} }, + .{ "fudai.iwate.jp", {} }, + .{ "fujisawa.iwate.jp", {} }, + .{ "hanamaki.iwate.jp", {} }, + .{ "hiraizumi.iwate.jp", {} }, + .{ "hirono.iwate.jp", {} }, + .{ "ichinohe.iwate.jp", {} }, + .{ "ichinoseki.iwate.jp", {} }, + .{ "iwaizumi.iwate.jp", {} }, + .{ "iwate.iwate.jp", {} }, + .{ "joboji.iwate.jp", {} }, + .{ "kamaishi.iwate.jp", {} }, + .{ "kanegasaki.iwate.jp", {} }, + .{ "karumai.iwate.jp", {} }, + .{ "kawai.iwate.jp", {} }, + .{ "kitakami.iwate.jp", {} }, + .{ "kuji.iwate.jp", {} }, + .{ "kunohe.iwate.jp", {} }, + .{ "kuzumaki.iwate.jp", {} }, + .{ "miyako.iwate.jp", {} }, + .{ "mizusawa.iwate.jp", {} }, + .{ "morioka.iwate.jp", {} }, + .{ "ninohe.iwate.jp", {} }, + .{ "noda.iwate.jp", {} }, + .{ "ofunato.iwate.jp", {} }, + .{ "oshu.iwate.jp", {} }, + .{ "otsuchi.iwate.jp", {} }, + .{ "rikuzentakata.iwate.jp", {} }, + .{ "shiwa.iwate.jp", {} }, + .{ "shizukuishi.iwate.jp", {} }, + .{ "sumita.iwate.jp", {} }, + .{ "tanohata.iwate.jp", {} }, + .{ "tono.iwate.jp", {} }, + .{ "yahaba.iwate.jp", {} }, + .{ "yamada.iwate.jp", {} }, + .{ "ayagawa.kagawa.jp", {} }, + .{ "higashikagawa.kagawa.jp", {} }, + .{ "kanonji.kagawa.jp", {} }, + .{ "kotohira.kagawa.jp", {} }, + .{ "manno.kagawa.jp", {} }, + .{ "marugame.kagawa.jp", {} }, + .{ "mitoyo.kagawa.jp", {} }, + .{ "naoshima.kagawa.jp", {} }, + .{ "sanuki.kagawa.jp", {} }, + .{ "tadotsu.kagawa.jp", {} }, + .{ "takamatsu.kagawa.jp", {} }, + .{ "tonosho.kagawa.jp", {} }, + .{ "uchinomi.kagawa.jp", {} }, + .{ "utazu.kagawa.jp", {} }, + .{ "zentsuji.kagawa.jp", {} }, + .{ "akune.kagoshima.jp", {} }, + .{ "amami.kagoshima.jp", {} }, + .{ "hioki.kagoshima.jp", {} }, + .{ "isa.kagoshima.jp", {} }, + .{ "isen.kagoshima.jp", {} }, + .{ "izumi.kagoshima.jp", {} }, + .{ "kagoshima.kagoshima.jp", {} }, + .{ "kanoya.kagoshima.jp", {} }, + .{ "kawanabe.kagoshima.jp", {} }, + .{ "kinko.kagoshima.jp", {} }, + .{ "kouyama.kagoshima.jp", {} }, + .{ "makurazaki.kagoshima.jp", {} }, + .{ "matsumoto.kagoshima.jp", {} }, + .{ "minamitane.kagoshima.jp", {} }, + .{ "nakatane.kagoshima.jp", {} }, + .{ "nishinoomote.kagoshima.jp", {} }, + .{ "satsumasendai.kagoshima.jp", {} }, + .{ "soo.kagoshima.jp", {} }, + .{ "tarumizu.kagoshima.jp", {} }, + .{ "yusui.kagoshima.jp", {} }, + .{ "aikawa.kanagawa.jp", {} }, + .{ "atsugi.kanagawa.jp", {} }, + .{ "ayase.kanagawa.jp", {} }, + .{ "chigasaki.kanagawa.jp", {} }, + .{ "ebina.kanagawa.jp", {} }, + .{ "fujisawa.kanagawa.jp", {} }, + .{ "hadano.kanagawa.jp", {} }, + .{ "hakone.kanagawa.jp", {} }, + .{ "hiratsuka.kanagawa.jp", {} }, + .{ "isehara.kanagawa.jp", {} }, + .{ "kaisei.kanagawa.jp", {} }, + .{ "kamakura.kanagawa.jp", {} }, + .{ "kiyokawa.kanagawa.jp", {} }, + .{ "matsuda.kanagawa.jp", {} }, + .{ "minamiashigara.kanagawa.jp", {} }, + .{ "miura.kanagawa.jp", {} }, + .{ "nakai.kanagawa.jp", {} }, + .{ "ninomiya.kanagawa.jp", {} }, + .{ "odawara.kanagawa.jp", {} }, + .{ "oi.kanagawa.jp", {} }, + .{ "oiso.kanagawa.jp", {} }, + .{ "sagamihara.kanagawa.jp", {} }, + .{ "samukawa.kanagawa.jp", {} }, + .{ "tsukui.kanagawa.jp", {} }, + .{ "yamakita.kanagawa.jp", {} }, + .{ "yamato.kanagawa.jp", {} }, + .{ "yokosuka.kanagawa.jp", {} }, + .{ "yugawara.kanagawa.jp", {} }, + .{ "zama.kanagawa.jp", {} }, + .{ "zushi.kanagawa.jp", {} }, + .{ "aki.kochi.jp", {} }, + .{ "geisei.kochi.jp", {} }, + .{ "hidaka.kochi.jp", {} }, + .{ "higashitsuno.kochi.jp", {} }, + .{ "ino.kochi.jp", {} }, + .{ "kagami.kochi.jp", {} }, + .{ "kami.kochi.jp", {} }, + .{ "kitagawa.kochi.jp", {} }, + .{ "kochi.kochi.jp", {} }, + .{ "mihara.kochi.jp", {} }, + .{ "motoyama.kochi.jp", {} }, + .{ "muroto.kochi.jp", {} }, + .{ "nahari.kochi.jp", {} }, + .{ "nakamura.kochi.jp", {} }, + .{ "nankoku.kochi.jp", {} }, + .{ "nishitosa.kochi.jp", {} }, + .{ "niyodogawa.kochi.jp", {} }, + .{ "ochi.kochi.jp", {} }, + .{ "okawa.kochi.jp", {} }, + .{ "otoyo.kochi.jp", {} }, + .{ "otsuki.kochi.jp", {} }, + .{ "sakawa.kochi.jp", {} }, + .{ "sukumo.kochi.jp", {} }, + .{ "susaki.kochi.jp", {} }, + .{ "tosa.kochi.jp", {} }, + .{ "tosashimizu.kochi.jp", {} }, + .{ "toyo.kochi.jp", {} }, + .{ "tsuno.kochi.jp", {} }, + .{ "umaji.kochi.jp", {} }, + .{ "yasuda.kochi.jp", {} }, + .{ "yusuhara.kochi.jp", {} }, + .{ "amakusa.kumamoto.jp", {} }, + .{ "arao.kumamoto.jp", {} }, + .{ "aso.kumamoto.jp", {} }, + .{ "choyo.kumamoto.jp", {} }, + .{ "gyokuto.kumamoto.jp", {} }, + .{ "kamiamakusa.kumamoto.jp", {} }, + .{ "kikuchi.kumamoto.jp", {} }, + .{ "kumamoto.kumamoto.jp", {} }, + .{ "mashiki.kumamoto.jp", {} }, + .{ "mifune.kumamoto.jp", {} }, + .{ "minamata.kumamoto.jp", {} }, + .{ "minamioguni.kumamoto.jp", {} }, + .{ "nagasu.kumamoto.jp", {} }, + .{ "nishihara.kumamoto.jp", {} }, + .{ "oguni.kumamoto.jp", {} }, + .{ "ozu.kumamoto.jp", {} }, + .{ "sumoto.kumamoto.jp", {} }, + .{ "takamori.kumamoto.jp", {} }, + .{ "uki.kumamoto.jp", {} }, + .{ "uto.kumamoto.jp", {} }, + .{ "yamaga.kumamoto.jp", {} }, + .{ "yamato.kumamoto.jp", {} }, + .{ "yatsushiro.kumamoto.jp", {} }, + .{ "ayabe.kyoto.jp", {} }, + .{ "fukuchiyama.kyoto.jp", {} }, + .{ "higashiyama.kyoto.jp", {} }, + .{ "ide.kyoto.jp", {} }, + .{ "ine.kyoto.jp", {} }, + .{ "joyo.kyoto.jp", {} }, + .{ "kameoka.kyoto.jp", {} }, + .{ "kamo.kyoto.jp", {} }, + .{ "kita.kyoto.jp", {} }, + .{ "kizu.kyoto.jp", {} }, + .{ "kumiyama.kyoto.jp", {} }, + .{ "kyotamba.kyoto.jp", {} }, + .{ "kyotanabe.kyoto.jp", {} }, + .{ "kyotango.kyoto.jp", {} }, + .{ "maizuru.kyoto.jp", {} }, + .{ "minami.kyoto.jp", {} }, + .{ "minamiyamashiro.kyoto.jp", {} }, + .{ "miyazu.kyoto.jp", {} }, + .{ "muko.kyoto.jp", {} }, + .{ "nagaokakyo.kyoto.jp", {} }, + .{ "nakagyo.kyoto.jp", {} }, + .{ "nantan.kyoto.jp", {} }, + .{ "oyamazaki.kyoto.jp", {} }, + .{ "sakyo.kyoto.jp", {} }, + .{ "seika.kyoto.jp", {} }, + .{ "tanabe.kyoto.jp", {} }, + .{ "uji.kyoto.jp", {} }, + .{ "ujitawara.kyoto.jp", {} }, + .{ "wazuka.kyoto.jp", {} }, + .{ "yamashina.kyoto.jp", {} }, + .{ "yawata.kyoto.jp", {} }, + .{ "asahi.mie.jp", {} }, + .{ "inabe.mie.jp", {} }, + .{ "ise.mie.jp", {} }, + .{ "kameyama.mie.jp", {} }, + .{ "kawagoe.mie.jp", {} }, + .{ "kiho.mie.jp", {} }, + .{ "kisosaki.mie.jp", {} }, + .{ "kiwa.mie.jp", {} }, + .{ "komono.mie.jp", {} }, + .{ "kumano.mie.jp", {} }, + .{ "kuwana.mie.jp", {} }, + .{ "matsusaka.mie.jp", {} }, + .{ "meiwa.mie.jp", {} }, + .{ "mihama.mie.jp", {} }, + .{ "minamiise.mie.jp", {} }, + .{ "misugi.mie.jp", {} }, + .{ "miyama.mie.jp", {} }, + .{ "nabari.mie.jp", {} }, + .{ "shima.mie.jp", {} }, + .{ "suzuka.mie.jp", {} }, + .{ "tado.mie.jp", {} }, + .{ "taiki.mie.jp", {} }, + .{ "taki.mie.jp", {} }, + .{ "tamaki.mie.jp", {} }, + .{ "toba.mie.jp", {} }, + .{ "tsu.mie.jp", {} }, + .{ "udono.mie.jp", {} }, + .{ "ureshino.mie.jp", {} }, + .{ "watarai.mie.jp", {} }, + .{ "yokkaichi.mie.jp", {} }, + .{ "furukawa.miyagi.jp", {} }, + .{ "higashimatsushima.miyagi.jp", {} }, + .{ "ishinomaki.miyagi.jp", {} }, + .{ "iwanuma.miyagi.jp", {} }, + .{ "kakuda.miyagi.jp", {} }, + .{ "kami.miyagi.jp", {} }, + .{ "kawasaki.miyagi.jp", {} }, + .{ "marumori.miyagi.jp", {} }, + .{ "matsushima.miyagi.jp", {} }, + .{ "minamisanriku.miyagi.jp", {} }, + .{ "misato.miyagi.jp", {} }, + .{ "murata.miyagi.jp", {} }, + .{ "natori.miyagi.jp", {} }, + .{ "ogawara.miyagi.jp", {} }, + .{ "ohira.miyagi.jp", {} }, + .{ "onagawa.miyagi.jp", {} }, + .{ "osaki.miyagi.jp", {} }, + .{ "rifu.miyagi.jp", {} }, + .{ "semine.miyagi.jp", {} }, + .{ "shibata.miyagi.jp", {} }, + .{ "shichikashuku.miyagi.jp", {} }, + .{ "shikama.miyagi.jp", {} }, + .{ "shiogama.miyagi.jp", {} }, + .{ "shiroishi.miyagi.jp", {} }, + .{ "tagajo.miyagi.jp", {} }, + .{ "taiwa.miyagi.jp", {} }, + .{ "tome.miyagi.jp", {} }, + .{ "tomiya.miyagi.jp", {} }, + .{ "wakuya.miyagi.jp", {} }, + .{ "watari.miyagi.jp", {} }, + .{ "yamamoto.miyagi.jp", {} }, + .{ "zao.miyagi.jp", {} }, + .{ "aya.miyazaki.jp", {} }, + .{ "ebino.miyazaki.jp", {} }, + .{ "gokase.miyazaki.jp", {} }, + .{ "hyuga.miyazaki.jp", {} }, + .{ "kadogawa.miyazaki.jp", {} }, + .{ "kawaminami.miyazaki.jp", {} }, + .{ "kijo.miyazaki.jp", {} }, + .{ "kitagawa.miyazaki.jp", {} }, + .{ "kitakata.miyazaki.jp", {} }, + .{ "kitaura.miyazaki.jp", {} }, + .{ "kobayashi.miyazaki.jp", {} }, + .{ "kunitomi.miyazaki.jp", {} }, + .{ "kushima.miyazaki.jp", {} }, + .{ "mimata.miyazaki.jp", {} }, + .{ "miyakonojo.miyazaki.jp", {} }, + .{ "miyazaki.miyazaki.jp", {} }, + .{ "morotsuka.miyazaki.jp", {} }, + .{ "nichinan.miyazaki.jp", {} }, + .{ "nishimera.miyazaki.jp", {} }, + .{ "nobeoka.miyazaki.jp", {} }, + .{ "saito.miyazaki.jp", {} }, + .{ "shiiba.miyazaki.jp", {} }, + .{ "shintomi.miyazaki.jp", {} }, + .{ "takaharu.miyazaki.jp", {} }, + .{ "takanabe.miyazaki.jp", {} }, + .{ "takazaki.miyazaki.jp", {} }, + .{ "tsuno.miyazaki.jp", {} }, + .{ "achi.nagano.jp", {} }, + .{ "agematsu.nagano.jp", {} }, + .{ "anan.nagano.jp", {} }, + .{ "aoki.nagano.jp", {} }, + .{ "asahi.nagano.jp", {} }, + .{ "azumino.nagano.jp", {} }, + .{ "chikuhoku.nagano.jp", {} }, + .{ "chikuma.nagano.jp", {} }, + .{ "chino.nagano.jp", {} }, + .{ "fujimi.nagano.jp", {} }, + .{ "hakuba.nagano.jp", {} }, + .{ "hara.nagano.jp", {} }, + .{ "hiraya.nagano.jp", {} }, + .{ "iida.nagano.jp", {} }, + .{ "iijima.nagano.jp", {} }, + .{ "iiyama.nagano.jp", {} }, + .{ "iizuna.nagano.jp", {} }, + .{ "ikeda.nagano.jp", {} }, + .{ "ikusaka.nagano.jp", {} }, + .{ "ina.nagano.jp", {} }, + .{ "karuizawa.nagano.jp", {} }, + .{ "kawakami.nagano.jp", {} }, + .{ "kiso.nagano.jp", {} }, + .{ "kisofukushima.nagano.jp", {} }, + .{ "kitaaiki.nagano.jp", {} }, + .{ "komagane.nagano.jp", {} }, + .{ "komoro.nagano.jp", {} }, + .{ "matsukawa.nagano.jp", {} }, + .{ "matsumoto.nagano.jp", {} }, + .{ "miasa.nagano.jp", {} }, + .{ "minamiaiki.nagano.jp", {} }, + .{ "minamimaki.nagano.jp", {} }, + .{ "minamiminowa.nagano.jp", {} }, + .{ "minowa.nagano.jp", {} }, + .{ "miyada.nagano.jp", {} }, + .{ "miyota.nagano.jp", {} }, + .{ "mochizuki.nagano.jp", {} }, + .{ "nagano.nagano.jp", {} }, + .{ "nagawa.nagano.jp", {} }, + .{ "nagiso.nagano.jp", {} }, + .{ "nakagawa.nagano.jp", {} }, + .{ "nakano.nagano.jp", {} }, + .{ "nozawaonsen.nagano.jp", {} }, + .{ "obuse.nagano.jp", {} }, + .{ "ogawa.nagano.jp", {} }, + .{ "okaya.nagano.jp", {} }, + .{ "omachi.nagano.jp", {} }, + .{ "omi.nagano.jp", {} }, + .{ "ookuwa.nagano.jp", {} }, + .{ "ooshika.nagano.jp", {} }, + .{ "otaki.nagano.jp", {} }, + .{ "otari.nagano.jp", {} }, + .{ "sakae.nagano.jp", {} }, + .{ "sakaki.nagano.jp", {} }, + .{ "saku.nagano.jp", {} }, + .{ "sakuho.nagano.jp", {} }, + .{ "shimosuwa.nagano.jp", {} }, + .{ "shinanomachi.nagano.jp", {} }, + .{ "shiojiri.nagano.jp", {} }, + .{ "suwa.nagano.jp", {} }, + .{ "suzaka.nagano.jp", {} }, + .{ "takagi.nagano.jp", {} }, + .{ "takamori.nagano.jp", {} }, + .{ "takayama.nagano.jp", {} }, + .{ "tateshina.nagano.jp", {} }, + .{ "tatsuno.nagano.jp", {} }, + .{ "togakushi.nagano.jp", {} }, + .{ "togura.nagano.jp", {} }, + .{ "tomi.nagano.jp", {} }, + .{ "ueda.nagano.jp", {} }, + .{ "wada.nagano.jp", {} }, + .{ "yamagata.nagano.jp", {} }, + .{ "yamanouchi.nagano.jp", {} }, + .{ "yasaka.nagano.jp", {} }, + .{ "yasuoka.nagano.jp", {} }, + .{ "chijiwa.nagasaki.jp", {} }, + .{ "futsu.nagasaki.jp", {} }, + .{ "goto.nagasaki.jp", {} }, + .{ "hasami.nagasaki.jp", {} }, + .{ "hirado.nagasaki.jp", {} }, + .{ "iki.nagasaki.jp", {} }, + .{ "isahaya.nagasaki.jp", {} }, + .{ "kawatana.nagasaki.jp", {} }, + .{ "kuchinotsu.nagasaki.jp", {} }, + .{ "matsuura.nagasaki.jp", {} }, + .{ "nagasaki.nagasaki.jp", {} }, + .{ "obama.nagasaki.jp", {} }, + .{ "omura.nagasaki.jp", {} }, + .{ "oseto.nagasaki.jp", {} }, + .{ "saikai.nagasaki.jp", {} }, + .{ "sasebo.nagasaki.jp", {} }, + .{ "seihi.nagasaki.jp", {} }, + .{ "shimabara.nagasaki.jp", {} }, + .{ "shinkamigoto.nagasaki.jp", {} }, + .{ "togitsu.nagasaki.jp", {} }, + .{ "tsushima.nagasaki.jp", {} }, + .{ "unzen.nagasaki.jp", {} }, + .{ "ando.nara.jp", {} }, + .{ "gose.nara.jp", {} }, + .{ "heguri.nara.jp", {} }, + .{ "higashiyoshino.nara.jp", {} }, + .{ "ikaruga.nara.jp", {} }, + .{ "ikoma.nara.jp", {} }, + .{ "kamikitayama.nara.jp", {} }, + .{ "kanmaki.nara.jp", {} }, + .{ "kashiba.nara.jp", {} }, + .{ "kashihara.nara.jp", {} }, + .{ "katsuragi.nara.jp", {} }, + .{ "kawai.nara.jp", {} }, + .{ "kawakami.nara.jp", {} }, + .{ "kawanishi.nara.jp", {} }, + .{ "koryo.nara.jp", {} }, + .{ "kurotaki.nara.jp", {} }, + .{ "mitsue.nara.jp", {} }, + .{ "miyake.nara.jp", {} }, + .{ "nara.nara.jp", {} }, + .{ "nosegawa.nara.jp", {} }, + .{ "oji.nara.jp", {} }, + .{ "ouda.nara.jp", {} }, + .{ "oyodo.nara.jp", {} }, + .{ "sakurai.nara.jp", {} }, + .{ "sango.nara.jp", {} }, + .{ "shimoichi.nara.jp", {} }, + .{ "shimokitayama.nara.jp", {} }, + .{ "shinjo.nara.jp", {} }, + .{ "soni.nara.jp", {} }, + .{ "takatori.nara.jp", {} }, + .{ "tawaramoto.nara.jp", {} }, + .{ "tenkawa.nara.jp", {} }, + .{ "tenri.nara.jp", {} }, + .{ "uda.nara.jp", {} }, + .{ "yamatokoriyama.nara.jp", {} }, + .{ "yamatotakada.nara.jp", {} }, + .{ "yamazoe.nara.jp", {} }, + .{ "yoshino.nara.jp", {} }, + .{ "aga.niigata.jp", {} }, + .{ "agano.niigata.jp", {} }, + .{ "gosen.niigata.jp", {} }, + .{ "itoigawa.niigata.jp", {} }, + .{ "izumozaki.niigata.jp", {} }, + .{ "joetsu.niigata.jp", {} }, + .{ "kamo.niigata.jp", {} }, + .{ "kariwa.niigata.jp", {} }, + .{ "kashiwazaki.niigata.jp", {} }, + .{ "minamiuonuma.niigata.jp", {} }, + .{ "mitsuke.niigata.jp", {} }, + .{ "muika.niigata.jp", {} }, + .{ "murakami.niigata.jp", {} }, + .{ "myoko.niigata.jp", {} }, + .{ "nagaoka.niigata.jp", {} }, + .{ "niigata.niigata.jp", {} }, + .{ "ojiya.niigata.jp", {} }, + .{ "omi.niigata.jp", {} }, + .{ "sado.niigata.jp", {} }, + .{ "sanjo.niigata.jp", {} }, + .{ "seiro.niigata.jp", {} }, + .{ "seirou.niigata.jp", {} }, + .{ "sekikawa.niigata.jp", {} }, + .{ "shibata.niigata.jp", {} }, + .{ "tagami.niigata.jp", {} }, + .{ "tainai.niigata.jp", {} }, + .{ "tochio.niigata.jp", {} }, + .{ "tokamachi.niigata.jp", {} }, + .{ "tsubame.niigata.jp", {} }, + .{ "tsunan.niigata.jp", {} }, + .{ "uonuma.niigata.jp", {} }, + .{ "yahiko.niigata.jp", {} }, + .{ "yoita.niigata.jp", {} }, + .{ "yuzawa.niigata.jp", {} }, + .{ "beppu.oita.jp", {} }, + .{ "bungoono.oita.jp", {} }, + .{ "bungotakada.oita.jp", {} }, + .{ "hasama.oita.jp", {} }, + .{ "hiji.oita.jp", {} }, + .{ "himeshima.oita.jp", {} }, + .{ "hita.oita.jp", {} }, + .{ "kamitsue.oita.jp", {} }, + .{ "kokonoe.oita.jp", {} }, + .{ "kuju.oita.jp", {} }, + .{ "kunisaki.oita.jp", {} }, + .{ "kusu.oita.jp", {} }, + .{ "oita.oita.jp", {} }, + .{ "saiki.oita.jp", {} }, + .{ "taketa.oita.jp", {} }, + .{ "tsukumi.oita.jp", {} }, + .{ "usa.oita.jp", {} }, + .{ "usuki.oita.jp", {} }, + .{ "yufu.oita.jp", {} }, + .{ "akaiwa.okayama.jp", {} }, + .{ "asakuchi.okayama.jp", {} }, + .{ "bizen.okayama.jp", {} }, + .{ "hayashima.okayama.jp", {} }, + .{ "ibara.okayama.jp", {} }, + .{ "kagamino.okayama.jp", {} }, + .{ "kasaoka.okayama.jp", {} }, + .{ "kibichuo.okayama.jp", {} }, + .{ "kumenan.okayama.jp", {} }, + .{ "kurashiki.okayama.jp", {} }, + .{ "maniwa.okayama.jp", {} }, + .{ "misaki.okayama.jp", {} }, + .{ "nagi.okayama.jp", {} }, + .{ "niimi.okayama.jp", {} }, + .{ "nishiawakura.okayama.jp", {} }, + .{ "okayama.okayama.jp", {} }, + .{ "satosho.okayama.jp", {} }, + .{ "setouchi.okayama.jp", {} }, + .{ "shinjo.okayama.jp", {} }, + .{ "shoo.okayama.jp", {} }, + .{ "soja.okayama.jp", {} }, + .{ "takahashi.okayama.jp", {} }, + .{ "tamano.okayama.jp", {} }, + .{ "tsuyama.okayama.jp", {} }, + .{ "wake.okayama.jp", {} }, + .{ "yakage.okayama.jp", {} }, + .{ "aguni.okinawa.jp", {} }, + .{ "ginowan.okinawa.jp", {} }, + .{ "ginoza.okinawa.jp", {} }, + .{ "gushikami.okinawa.jp", {} }, + .{ "haebaru.okinawa.jp", {} }, + .{ "higashi.okinawa.jp", {} }, + .{ "hirara.okinawa.jp", {} }, + .{ "iheya.okinawa.jp", {} }, + .{ "ishigaki.okinawa.jp", {} }, + .{ "ishikawa.okinawa.jp", {} }, + .{ "itoman.okinawa.jp", {} }, + .{ "izena.okinawa.jp", {} }, + .{ "kadena.okinawa.jp", {} }, + .{ "kin.okinawa.jp", {} }, + .{ "kitadaito.okinawa.jp", {} }, + .{ "kitanakagusuku.okinawa.jp", {} }, + .{ "kumejima.okinawa.jp", {} }, + .{ "kunigami.okinawa.jp", {} }, + .{ "minamidaito.okinawa.jp", {} }, + .{ "motobu.okinawa.jp", {} }, + .{ "nago.okinawa.jp", {} }, + .{ "naha.okinawa.jp", {} }, + .{ "nakagusuku.okinawa.jp", {} }, + .{ "nakijin.okinawa.jp", {} }, + .{ "nanjo.okinawa.jp", {} }, + .{ "nishihara.okinawa.jp", {} }, + .{ "ogimi.okinawa.jp", {} }, + .{ "okinawa.okinawa.jp", {} }, + .{ "onna.okinawa.jp", {} }, + .{ "shimoji.okinawa.jp", {} }, + .{ "taketomi.okinawa.jp", {} }, + .{ "tarama.okinawa.jp", {} }, + .{ "tokashiki.okinawa.jp", {} }, + .{ "tomigusuku.okinawa.jp", {} }, + .{ "tonaki.okinawa.jp", {} }, + .{ "urasoe.okinawa.jp", {} }, + .{ "uruma.okinawa.jp", {} }, + .{ "yaese.okinawa.jp", {} }, + .{ "yomitan.okinawa.jp", {} }, + .{ "yonabaru.okinawa.jp", {} }, + .{ "yonaguni.okinawa.jp", {} }, + .{ "zamami.okinawa.jp", {} }, + .{ "abeno.osaka.jp", {} }, + .{ "chihayaakasaka.osaka.jp", {} }, + .{ "chuo.osaka.jp", {} }, + .{ "daito.osaka.jp", {} }, + .{ "fujiidera.osaka.jp", {} }, + .{ "habikino.osaka.jp", {} }, + .{ "hannan.osaka.jp", {} }, + .{ "higashiosaka.osaka.jp", {} }, + .{ "higashisumiyoshi.osaka.jp", {} }, + .{ "higashiyodogawa.osaka.jp", {} }, + .{ "hirakata.osaka.jp", {} }, + .{ "ibaraki.osaka.jp", {} }, + .{ "ikeda.osaka.jp", {} }, + .{ "izumi.osaka.jp", {} }, + .{ "izumiotsu.osaka.jp", {} }, + .{ "izumisano.osaka.jp", {} }, + .{ "kadoma.osaka.jp", {} }, + .{ "kaizuka.osaka.jp", {} }, + .{ "kanan.osaka.jp", {} }, + .{ "kashiwara.osaka.jp", {} }, + .{ "katano.osaka.jp", {} }, + .{ "kawachinagano.osaka.jp", {} }, + .{ "kishiwada.osaka.jp", {} }, + .{ "kita.osaka.jp", {} }, + .{ "kumatori.osaka.jp", {} }, + .{ "matsubara.osaka.jp", {} }, + .{ "minato.osaka.jp", {} }, + .{ "minoh.osaka.jp", {} }, + .{ "misaki.osaka.jp", {} }, + .{ "moriguchi.osaka.jp", {} }, + .{ "neyagawa.osaka.jp", {} }, + .{ "nishi.osaka.jp", {} }, + .{ "nose.osaka.jp", {} }, + .{ "osakasayama.osaka.jp", {} }, + .{ "sakai.osaka.jp", {} }, + .{ "sayama.osaka.jp", {} }, + .{ "sennan.osaka.jp", {} }, + .{ "settsu.osaka.jp", {} }, + .{ "shijonawate.osaka.jp", {} }, + .{ "shimamoto.osaka.jp", {} }, + .{ "suita.osaka.jp", {} }, + .{ "tadaoka.osaka.jp", {} }, + .{ "taishi.osaka.jp", {} }, + .{ "tajiri.osaka.jp", {} }, + .{ "takaishi.osaka.jp", {} }, + .{ "takatsuki.osaka.jp", {} }, + .{ "tondabayashi.osaka.jp", {} }, + .{ "toyonaka.osaka.jp", {} }, + .{ "toyono.osaka.jp", {} }, + .{ "yao.osaka.jp", {} }, + .{ "ariake.saga.jp", {} }, + .{ "arita.saga.jp", {} }, + .{ "fukudomi.saga.jp", {} }, + .{ "genkai.saga.jp", {} }, + .{ "hamatama.saga.jp", {} }, + .{ "hizen.saga.jp", {} }, + .{ "imari.saga.jp", {} }, + .{ "kamimine.saga.jp", {} }, + .{ "kanzaki.saga.jp", {} }, + .{ "karatsu.saga.jp", {} }, + .{ "kashima.saga.jp", {} }, + .{ "kitagata.saga.jp", {} }, + .{ "kitahata.saga.jp", {} }, + .{ "kiyama.saga.jp", {} }, + .{ "kouhoku.saga.jp", {} }, + .{ "kyuragi.saga.jp", {} }, + .{ "nishiarita.saga.jp", {} }, + .{ "ogi.saga.jp", {} }, + .{ "omachi.saga.jp", {} }, + .{ "ouchi.saga.jp", {} }, + .{ "saga.saga.jp", {} }, + .{ "shiroishi.saga.jp", {} }, + .{ "taku.saga.jp", {} }, + .{ "tara.saga.jp", {} }, + .{ "tosu.saga.jp", {} }, + .{ "yoshinogari.saga.jp", {} }, + .{ "arakawa.saitama.jp", {} }, + .{ "asaka.saitama.jp", {} }, + .{ "chichibu.saitama.jp", {} }, + .{ "fujimi.saitama.jp", {} }, + .{ "fujimino.saitama.jp", {} }, + .{ "fukaya.saitama.jp", {} }, + .{ "hanno.saitama.jp", {} }, + .{ "hanyu.saitama.jp", {} }, + .{ "hasuda.saitama.jp", {} }, + .{ "hatogaya.saitama.jp", {} }, + .{ "hatoyama.saitama.jp", {} }, + .{ "hidaka.saitama.jp", {} }, + .{ "higashichichibu.saitama.jp", {} }, + .{ "higashimatsuyama.saitama.jp", {} }, + .{ "honjo.saitama.jp", {} }, + .{ "ina.saitama.jp", {} }, + .{ "iruma.saitama.jp", {} }, + .{ "iwatsuki.saitama.jp", {} }, + .{ "kamiizumi.saitama.jp", {} }, + .{ "kamikawa.saitama.jp", {} }, + .{ "kamisato.saitama.jp", {} }, + .{ "kasukabe.saitama.jp", {} }, + .{ "kawagoe.saitama.jp", {} }, + .{ "kawaguchi.saitama.jp", {} }, + .{ "kawajima.saitama.jp", {} }, + .{ "kazo.saitama.jp", {} }, + .{ "kitamoto.saitama.jp", {} }, + .{ "koshigaya.saitama.jp", {} }, + .{ "kounosu.saitama.jp", {} }, + .{ "kuki.saitama.jp", {} }, + .{ "kumagaya.saitama.jp", {} }, + .{ "matsubushi.saitama.jp", {} }, + .{ "minano.saitama.jp", {} }, + .{ "misato.saitama.jp", {} }, + .{ "miyashiro.saitama.jp", {} }, + .{ "miyoshi.saitama.jp", {} }, + .{ "moroyama.saitama.jp", {} }, + .{ "nagatoro.saitama.jp", {} }, + .{ "namegawa.saitama.jp", {} }, + .{ "niiza.saitama.jp", {} }, + .{ "ogano.saitama.jp", {} }, + .{ "ogawa.saitama.jp", {} }, + .{ "ogose.saitama.jp", {} }, + .{ "okegawa.saitama.jp", {} }, + .{ "omiya.saitama.jp", {} }, + .{ "otaki.saitama.jp", {} }, + .{ "ranzan.saitama.jp", {} }, + .{ "ryokami.saitama.jp", {} }, + .{ "saitama.saitama.jp", {} }, + .{ "sakado.saitama.jp", {} }, + .{ "satte.saitama.jp", {} }, + .{ "sayama.saitama.jp", {} }, + .{ "shiki.saitama.jp", {} }, + .{ "shiraoka.saitama.jp", {} }, + .{ "soka.saitama.jp", {} }, + .{ "sugito.saitama.jp", {} }, + .{ "toda.saitama.jp", {} }, + .{ "tokigawa.saitama.jp", {} }, + .{ "tokorozawa.saitama.jp", {} }, + .{ "tsurugashima.saitama.jp", {} }, + .{ "urawa.saitama.jp", {} }, + .{ "warabi.saitama.jp", {} }, + .{ "yashio.saitama.jp", {} }, + .{ "yokoze.saitama.jp", {} }, + .{ "yono.saitama.jp", {} }, + .{ "yorii.saitama.jp", {} }, + .{ "yoshida.saitama.jp", {} }, + .{ "yoshikawa.saitama.jp", {} }, + .{ "yoshimi.saitama.jp", {} }, + .{ "aisho.shiga.jp", {} }, + .{ "gamo.shiga.jp", {} }, + .{ "higashiomi.shiga.jp", {} }, + .{ "hikone.shiga.jp", {} }, + .{ "koka.shiga.jp", {} }, + .{ "konan.shiga.jp", {} }, + .{ "kosei.shiga.jp", {} }, + .{ "koto.shiga.jp", {} }, + .{ "kusatsu.shiga.jp", {} }, + .{ "maibara.shiga.jp", {} }, + .{ "moriyama.shiga.jp", {} }, + .{ "nagahama.shiga.jp", {} }, + .{ "nishiazai.shiga.jp", {} }, + .{ "notogawa.shiga.jp", {} }, + .{ "omihachiman.shiga.jp", {} }, + .{ "otsu.shiga.jp", {} }, + .{ "ritto.shiga.jp", {} }, + .{ "ryuoh.shiga.jp", {} }, + .{ "takashima.shiga.jp", {} }, + .{ "takatsuki.shiga.jp", {} }, + .{ "torahime.shiga.jp", {} }, + .{ "toyosato.shiga.jp", {} }, + .{ "yasu.shiga.jp", {} }, + .{ "akagi.shimane.jp", {} }, + .{ "ama.shimane.jp", {} }, + .{ "gotsu.shimane.jp", {} }, + .{ "hamada.shimane.jp", {} }, + .{ "higashiizumo.shimane.jp", {} }, + .{ "hikawa.shimane.jp", {} }, + .{ "hikimi.shimane.jp", {} }, + .{ "izumo.shimane.jp", {} }, + .{ "kakinoki.shimane.jp", {} }, + .{ "masuda.shimane.jp", {} }, + .{ "matsue.shimane.jp", {} }, + .{ "misato.shimane.jp", {} }, + .{ "nishinoshima.shimane.jp", {} }, + .{ "ohda.shimane.jp", {} }, + .{ "okinoshima.shimane.jp", {} }, + .{ "okuizumo.shimane.jp", {} }, + .{ "shimane.shimane.jp", {} }, + .{ "tamayu.shimane.jp", {} }, + .{ "tsuwano.shimane.jp", {} }, + .{ "unnan.shimane.jp", {} }, + .{ "yakumo.shimane.jp", {} }, + .{ "yasugi.shimane.jp", {} }, + .{ "yatsuka.shimane.jp", {} }, + .{ "arai.shizuoka.jp", {} }, + .{ "atami.shizuoka.jp", {} }, + .{ "fuji.shizuoka.jp", {} }, + .{ "fujieda.shizuoka.jp", {} }, + .{ "fujikawa.shizuoka.jp", {} }, + .{ "fujinomiya.shizuoka.jp", {} }, + .{ "fukuroi.shizuoka.jp", {} }, + .{ "gotemba.shizuoka.jp", {} }, + .{ "haibara.shizuoka.jp", {} }, + .{ "hamamatsu.shizuoka.jp", {} }, + .{ "higashiizu.shizuoka.jp", {} }, + .{ "ito.shizuoka.jp", {} }, + .{ "iwata.shizuoka.jp", {} }, + .{ "izu.shizuoka.jp", {} }, + .{ "izunokuni.shizuoka.jp", {} }, + .{ "kakegawa.shizuoka.jp", {} }, + .{ "kannami.shizuoka.jp", {} }, + .{ "kawanehon.shizuoka.jp", {} }, + .{ "kawazu.shizuoka.jp", {} }, + .{ "kikugawa.shizuoka.jp", {} }, + .{ "kosai.shizuoka.jp", {} }, + .{ "makinohara.shizuoka.jp", {} }, + .{ "matsuzaki.shizuoka.jp", {} }, + .{ "minamiizu.shizuoka.jp", {} }, + .{ "mishima.shizuoka.jp", {} }, + .{ "morimachi.shizuoka.jp", {} }, + .{ "nishiizu.shizuoka.jp", {} }, + .{ "numazu.shizuoka.jp", {} }, + .{ "omaezaki.shizuoka.jp", {} }, + .{ "shimada.shizuoka.jp", {} }, + .{ "shimizu.shizuoka.jp", {} }, + .{ "shimoda.shizuoka.jp", {} }, + .{ "shizuoka.shizuoka.jp", {} }, + .{ "susono.shizuoka.jp", {} }, + .{ "yaizu.shizuoka.jp", {} }, + .{ "yoshida.shizuoka.jp", {} }, + .{ "ashikaga.tochigi.jp", {} }, + .{ "bato.tochigi.jp", {} }, + .{ "haga.tochigi.jp", {} }, + .{ "ichikai.tochigi.jp", {} }, + .{ "iwafune.tochigi.jp", {} }, + .{ "kaminokawa.tochigi.jp", {} }, + .{ "kanuma.tochigi.jp", {} }, + .{ "karasuyama.tochigi.jp", {} }, + .{ "kuroiso.tochigi.jp", {} }, + .{ "mashiko.tochigi.jp", {} }, + .{ "mibu.tochigi.jp", {} }, + .{ "moka.tochigi.jp", {} }, + .{ "motegi.tochigi.jp", {} }, + .{ "nasu.tochigi.jp", {} }, + .{ "nasushiobara.tochigi.jp", {} }, + .{ "nikko.tochigi.jp", {} }, + .{ "nishikata.tochigi.jp", {} }, + .{ "nogi.tochigi.jp", {} }, + .{ "ohira.tochigi.jp", {} }, + .{ "ohtawara.tochigi.jp", {} }, + .{ "oyama.tochigi.jp", {} }, + .{ "sakura.tochigi.jp", {} }, + .{ "sano.tochigi.jp", {} }, + .{ "shimotsuke.tochigi.jp", {} }, + .{ "shioya.tochigi.jp", {} }, + .{ "takanezawa.tochigi.jp", {} }, + .{ "tochigi.tochigi.jp", {} }, + .{ "tsuga.tochigi.jp", {} }, + .{ "ujiie.tochigi.jp", {} }, + .{ "utsunomiya.tochigi.jp", {} }, + .{ "yaita.tochigi.jp", {} }, + .{ "aizumi.tokushima.jp", {} }, + .{ "anan.tokushima.jp", {} }, + .{ "ichiba.tokushima.jp", {} }, + .{ "itano.tokushima.jp", {} }, + .{ "kainan.tokushima.jp", {} }, + .{ "komatsushima.tokushima.jp", {} }, + .{ "matsushige.tokushima.jp", {} }, + .{ "mima.tokushima.jp", {} }, + .{ "minami.tokushima.jp", {} }, + .{ "miyoshi.tokushima.jp", {} }, + .{ "mugi.tokushima.jp", {} }, + .{ "nakagawa.tokushima.jp", {} }, + .{ "naruto.tokushima.jp", {} }, + .{ "sanagochi.tokushima.jp", {} }, + .{ "shishikui.tokushima.jp", {} }, + .{ "tokushima.tokushima.jp", {} }, + .{ "wajiki.tokushima.jp", {} }, + .{ "adachi.tokyo.jp", {} }, + .{ "akiruno.tokyo.jp", {} }, + .{ "akishima.tokyo.jp", {} }, + .{ "aogashima.tokyo.jp", {} }, + .{ "arakawa.tokyo.jp", {} }, + .{ "bunkyo.tokyo.jp", {} }, + .{ "chiyoda.tokyo.jp", {} }, + .{ "chofu.tokyo.jp", {} }, + .{ "chuo.tokyo.jp", {} }, + .{ "edogawa.tokyo.jp", {} }, + .{ "fuchu.tokyo.jp", {} }, + .{ "fussa.tokyo.jp", {} }, + .{ "hachijo.tokyo.jp", {} }, + .{ "hachioji.tokyo.jp", {} }, + .{ "hamura.tokyo.jp", {} }, + .{ "higashikurume.tokyo.jp", {} }, + .{ "higashimurayama.tokyo.jp", {} }, + .{ "higashiyamato.tokyo.jp", {} }, + .{ "hino.tokyo.jp", {} }, + .{ "hinode.tokyo.jp", {} }, + .{ "hinohara.tokyo.jp", {} }, + .{ "inagi.tokyo.jp", {} }, + .{ "itabashi.tokyo.jp", {} }, + .{ "katsushika.tokyo.jp", {} }, + .{ "kita.tokyo.jp", {} }, + .{ "kiyose.tokyo.jp", {} }, + .{ "kodaira.tokyo.jp", {} }, + .{ "koganei.tokyo.jp", {} }, + .{ "kokubunji.tokyo.jp", {} }, + .{ "komae.tokyo.jp", {} }, + .{ "koto.tokyo.jp", {} }, + .{ "kouzushima.tokyo.jp", {} }, + .{ "kunitachi.tokyo.jp", {} }, + .{ "machida.tokyo.jp", {} }, + .{ "meguro.tokyo.jp", {} }, + .{ "minato.tokyo.jp", {} }, + .{ "mitaka.tokyo.jp", {} }, + .{ "mizuho.tokyo.jp", {} }, + .{ "musashimurayama.tokyo.jp", {} }, + .{ "musashino.tokyo.jp", {} }, + .{ "nakano.tokyo.jp", {} }, + .{ "nerima.tokyo.jp", {} }, + .{ "ogasawara.tokyo.jp", {} }, + .{ "okutama.tokyo.jp", {} }, + .{ "ome.tokyo.jp", {} }, + .{ "oshima.tokyo.jp", {} }, + .{ "ota.tokyo.jp", {} }, + .{ "setagaya.tokyo.jp", {} }, + .{ "shibuya.tokyo.jp", {} }, + .{ "shinagawa.tokyo.jp", {} }, + .{ "shinjuku.tokyo.jp", {} }, + .{ "suginami.tokyo.jp", {} }, + .{ "sumida.tokyo.jp", {} }, + .{ "tachikawa.tokyo.jp", {} }, + .{ "taito.tokyo.jp", {} }, + .{ "tama.tokyo.jp", {} }, + .{ "toshima.tokyo.jp", {} }, + .{ "chizu.tottori.jp", {} }, + .{ "hino.tottori.jp", {} }, + .{ "kawahara.tottori.jp", {} }, + .{ "koge.tottori.jp", {} }, + .{ "kotoura.tottori.jp", {} }, + .{ "misasa.tottori.jp", {} }, + .{ "nanbu.tottori.jp", {} }, + .{ "nichinan.tottori.jp", {} }, + .{ "sakaiminato.tottori.jp", {} }, + .{ "tottori.tottori.jp", {} }, + .{ "wakasa.tottori.jp", {} }, + .{ "yazu.tottori.jp", {} }, + .{ "yonago.tottori.jp", {} }, + .{ "asahi.toyama.jp", {} }, + .{ "fuchu.toyama.jp", {} }, + .{ "fukumitsu.toyama.jp", {} }, + .{ "funahashi.toyama.jp", {} }, + .{ "himi.toyama.jp", {} }, + .{ "imizu.toyama.jp", {} }, + .{ "inami.toyama.jp", {} }, + .{ "johana.toyama.jp", {} }, + .{ "kamiichi.toyama.jp", {} }, + .{ "kurobe.toyama.jp", {} }, + .{ "nakaniikawa.toyama.jp", {} }, + .{ "namerikawa.toyama.jp", {} }, + .{ "nanto.toyama.jp", {} }, + .{ "nyuzen.toyama.jp", {} }, + .{ "oyabe.toyama.jp", {} }, + .{ "taira.toyama.jp", {} }, + .{ "takaoka.toyama.jp", {} }, + .{ "tateyama.toyama.jp", {} }, + .{ "toga.toyama.jp", {} }, + .{ "tonami.toyama.jp", {} }, + .{ "toyama.toyama.jp", {} }, + .{ "unazuki.toyama.jp", {} }, + .{ "uozu.toyama.jp", {} }, + .{ "yamada.toyama.jp", {} }, + .{ "arida.wakayama.jp", {} }, + .{ "aridagawa.wakayama.jp", {} }, + .{ "gobo.wakayama.jp", {} }, + .{ "hashimoto.wakayama.jp", {} }, + .{ "hidaka.wakayama.jp", {} }, + .{ "hirogawa.wakayama.jp", {} }, + .{ "inami.wakayama.jp", {} }, + .{ "iwade.wakayama.jp", {} }, + .{ "kainan.wakayama.jp", {} }, + .{ "kamitonda.wakayama.jp", {} }, + .{ "katsuragi.wakayama.jp", {} }, + .{ "kimino.wakayama.jp", {} }, + .{ "kinokawa.wakayama.jp", {} }, + .{ "kitayama.wakayama.jp", {} }, + .{ "koya.wakayama.jp", {} }, + .{ "koza.wakayama.jp", {} }, + .{ "kozagawa.wakayama.jp", {} }, + .{ "kudoyama.wakayama.jp", {} }, + .{ "kushimoto.wakayama.jp", {} }, + .{ "mihama.wakayama.jp", {} }, + .{ "misato.wakayama.jp", {} }, + .{ "nachikatsuura.wakayama.jp", {} }, + .{ "shingu.wakayama.jp", {} }, + .{ "shirahama.wakayama.jp", {} }, + .{ "taiji.wakayama.jp", {} }, + .{ "tanabe.wakayama.jp", {} }, + .{ "wakayama.wakayama.jp", {} }, + .{ "yuasa.wakayama.jp", {} }, + .{ "yura.wakayama.jp", {} }, + .{ "asahi.yamagata.jp", {} }, + .{ "funagata.yamagata.jp", {} }, + .{ "higashine.yamagata.jp", {} }, + .{ "iide.yamagata.jp", {} }, + .{ "kahoku.yamagata.jp", {} }, + .{ "kaminoyama.yamagata.jp", {} }, + .{ "kaneyama.yamagata.jp", {} }, + .{ "kawanishi.yamagata.jp", {} }, + .{ "mamurogawa.yamagata.jp", {} }, + .{ "mikawa.yamagata.jp", {} }, + .{ "murayama.yamagata.jp", {} }, + .{ "nagai.yamagata.jp", {} }, + .{ "nakayama.yamagata.jp", {} }, + .{ "nanyo.yamagata.jp", {} }, + .{ "nishikawa.yamagata.jp", {} }, + .{ "obanazawa.yamagata.jp", {} }, + .{ "oe.yamagata.jp", {} }, + .{ "oguni.yamagata.jp", {} }, + .{ "ohkura.yamagata.jp", {} }, + .{ "oishida.yamagata.jp", {} }, + .{ "sagae.yamagata.jp", {} }, + .{ "sakata.yamagata.jp", {} }, + .{ "sakegawa.yamagata.jp", {} }, + .{ "shinjo.yamagata.jp", {} }, + .{ "shirataka.yamagata.jp", {} }, + .{ "shonai.yamagata.jp", {} }, + .{ "takahata.yamagata.jp", {} }, + .{ "tendo.yamagata.jp", {} }, + .{ "tozawa.yamagata.jp", {} }, + .{ "tsuruoka.yamagata.jp", {} }, + .{ "yamagata.yamagata.jp", {} }, + .{ "yamanobe.yamagata.jp", {} }, + .{ "yonezawa.yamagata.jp", {} }, + .{ "yuza.yamagata.jp", {} }, + .{ "abu.yamaguchi.jp", {} }, + .{ "hagi.yamaguchi.jp", {} }, + .{ "hikari.yamaguchi.jp", {} }, + .{ "hofu.yamaguchi.jp", {} }, + .{ "iwakuni.yamaguchi.jp", {} }, + .{ "kudamatsu.yamaguchi.jp", {} }, + .{ "mitou.yamaguchi.jp", {} }, + .{ "nagato.yamaguchi.jp", {} }, + .{ "oshima.yamaguchi.jp", {} }, + .{ "shimonoseki.yamaguchi.jp", {} }, + .{ "shunan.yamaguchi.jp", {} }, + .{ "tabuse.yamaguchi.jp", {} }, + .{ "tokuyama.yamaguchi.jp", {} }, + .{ "toyota.yamaguchi.jp", {} }, + .{ "ube.yamaguchi.jp", {} }, + .{ "yuu.yamaguchi.jp", {} }, + .{ "chuo.yamanashi.jp", {} }, + .{ "doshi.yamanashi.jp", {} }, + .{ "fuefuki.yamanashi.jp", {} }, + .{ "fujikawa.yamanashi.jp", {} }, + .{ "fujikawaguchiko.yamanashi.jp", {} }, + .{ "fujiyoshida.yamanashi.jp", {} }, + .{ "hayakawa.yamanashi.jp", {} }, + .{ "hokuto.yamanashi.jp", {} }, + .{ "ichikawamisato.yamanashi.jp", {} }, + .{ "kai.yamanashi.jp", {} }, + .{ "kofu.yamanashi.jp", {} }, + .{ "koshu.yamanashi.jp", {} }, + .{ "kosuge.yamanashi.jp", {} }, + .{ "minami-alps.yamanashi.jp", {} }, + .{ "minobu.yamanashi.jp", {} }, + .{ "nakamichi.yamanashi.jp", {} }, + .{ "nanbu.yamanashi.jp", {} }, + .{ "narusawa.yamanashi.jp", {} }, + .{ "nirasaki.yamanashi.jp", {} }, + .{ "nishikatsura.yamanashi.jp", {} }, + .{ "oshino.yamanashi.jp", {} }, + .{ "otsuki.yamanashi.jp", {} }, + .{ "showa.yamanashi.jp", {} }, + .{ "tabayama.yamanashi.jp", {} }, + .{ "tsuru.yamanashi.jp", {} }, + .{ "uenohara.yamanashi.jp", {} }, + .{ "yamanakako.yamanashi.jp", {} }, + .{ "yamanashi.yamanashi.jp", {} }, + .{ "ke", {} }, + .{ "ac.ke", {} }, + .{ "co.ke", {} }, + .{ "go.ke", {} }, + .{ "info.ke", {} }, + .{ "me.ke", {} }, + .{ "mobi.ke", {} }, + .{ "ne.ke", {} }, + .{ "or.ke", {} }, + .{ "sc.ke", {} }, + .{ "kg", {} }, + .{ "com.kg", {} }, + .{ "edu.kg", {} }, + .{ "gov.kg", {} }, + .{ "mil.kg", {} }, + .{ "net.kg", {} }, + .{ "org.kg", {} }, + .{ "*.kh", {} }, + .{ "ki", {} }, + .{ "biz.ki", {} }, + .{ "com.ki", {} }, + .{ "edu.ki", {} }, + .{ "gov.ki", {} }, + .{ "info.ki", {} }, + .{ "net.ki", {} }, + .{ "org.ki", {} }, + .{ "km", {} }, + .{ "ass.km", {} }, + .{ "com.km", {} }, + .{ "edu.km", {} }, + .{ "gov.km", {} }, + .{ "mil.km", {} }, + .{ "nom.km", {} }, + .{ "org.km", {} }, + .{ "prd.km", {} }, + .{ "tm.km", {} }, + .{ "asso.km", {} }, + .{ "coop.km", {} }, + .{ "gouv.km", {} }, + .{ "medecin.km", {} }, + .{ "notaires.km", {} }, + .{ "pharmaciens.km", {} }, + .{ "presse.km", {} }, + .{ "veterinaire.km", {} }, + .{ "kn", {} }, + .{ "edu.kn", {} }, + .{ "gov.kn", {} }, + .{ "net.kn", {} }, + .{ "org.kn", {} }, + .{ "kp", {} }, + .{ "com.kp", {} }, + .{ "edu.kp", {} }, + .{ "gov.kp", {} }, + .{ "org.kp", {} }, + .{ "rep.kp", {} }, + .{ "tra.kp", {} }, + .{ "kr", {} }, + .{ "ac.kr", {} }, + .{ "co.kr", {} }, + .{ "es.kr", {} }, + .{ "go.kr", {} }, + .{ "hs.kr", {} }, + .{ "kg.kr", {} }, + .{ "mil.kr", {} }, + .{ "ms.kr", {} }, + .{ "ne.kr", {} }, + .{ "or.kr", {} }, + .{ "pe.kr", {} }, + .{ "re.kr", {} }, + .{ "sc.kr", {} }, + .{ "busan.kr", {} }, + .{ "chungbuk.kr", {} }, + .{ "chungnam.kr", {} }, + .{ "daegu.kr", {} }, + .{ "daejeon.kr", {} }, + .{ "gangwon.kr", {} }, + .{ "gwangju.kr", {} }, + .{ "gyeongbuk.kr", {} }, + .{ "gyeonggi.kr", {} }, + .{ "gyeongnam.kr", {} }, + .{ "incheon.kr", {} }, + .{ "jeju.kr", {} }, + .{ "jeonbuk.kr", {} }, + .{ "jeonnam.kr", {} }, + .{ "seoul.kr", {} }, + .{ "ulsan.kr", {} }, + .{ "kw", {} }, + .{ "com.kw", {} }, + .{ "edu.kw", {} }, + .{ "emb.kw", {} }, + .{ "gov.kw", {} }, + .{ "ind.kw", {} }, + .{ "net.kw", {} }, + .{ "org.kw", {} }, + .{ "ky", {} }, + .{ "com.ky", {} }, + .{ "edu.ky", {} }, + .{ "net.ky", {} }, + .{ "org.ky", {} }, + .{ "kz", {} }, + .{ "com.kz", {} }, + .{ "edu.kz", {} }, + .{ "gov.kz", {} }, + .{ "mil.kz", {} }, + .{ "net.kz", {} }, + .{ "org.kz", {} }, + .{ "la", {} }, + .{ "com.la", {} }, + .{ "edu.la", {} }, + .{ "gov.la", {} }, + .{ "info.la", {} }, + .{ "int.la", {} }, + .{ "net.la", {} }, + .{ "org.la", {} }, + .{ "per.la", {} }, + .{ "lb", {} }, + .{ "com.lb", {} }, + .{ "edu.lb", {} }, + .{ "gov.lb", {} }, + .{ "net.lb", {} }, + .{ "org.lb", {} }, + .{ "lc", {} }, + .{ "co.lc", {} }, + .{ "com.lc", {} }, + .{ "edu.lc", {} }, + .{ "gov.lc", {} }, + .{ "net.lc", {} }, + .{ "org.lc", {} }, + .{ "li", {} }, + .{ "lk", {} }, + .{ "ac.lk", {} }, + .{ "assn.lk", {} }, + .{ "com.lk", {} }, + .{ "edu.lk", {} }, + .{ "gov.lk", {} }, + .{ "grp.lk", {} }, + .{ "hotel.lk", {} }, + .{ "int.lk", {} }, + .{ "ltd.lk", {} }, + .{ "net.lk", {} }, + .{ "ngo.lk", {} }, + .{ "org.lk", {} }, + .{ "sch.lk", {} }, + .{ "soc.lk", {} }, + .{ "web.lk", {} }, + .{ "lr", {} }, + .{ "com.lr", {} }, + .{ "edu.lr", {} }, + .{ "gov.lr", {} }, + .{ "net.lr", {} }, + .{ "org.lr", {} }, + .{ "ls", {} }, + .{ "ac.ls", {} }, + .{ "biz.ls", {} }, + .{ "co.ls", {} }, + .{ "edu.ls", {} }, + .{ "gov.ls", {} }, + .{ "info.ls", {} }, + .{ "net.ls", {} }, + .{ "org.ls", {} }, + .{ "sc.ls", {} }, + .{ "lt", {} }, + .{ "gov.lt", {} }, + .{ "lu", {} }, + .{ "lv", {} }, + .{ "asn.lv", {} }, + .{ "com.lv", {} }, + .{ "conf.lv", {} }, + .{ "edu.lv", {} }, + .{ "gov.lv", {} }, + .{ "id.lv", {} }, + .{ "mil.lv", {} }, + .{ "net.lv", {} }, + .{ "org.lv", {} }, + .{ "ly", {} }, + .{ "com.ly", {} }, + .{ "edu.ly", {} }, + .{ "gov.ly", {} }, + .{ "id.ly", {} }, + .{ "med.ly", {} }, + .{ "net.ly", {} }, + .{ "org.ly", {} }, + .{ "plc.ly", {} }, + .{ "sch.ly", {} }, + .{ "ma", {} }, + .{ "ac.ma", {} }, + .{ "co.ma", {} }, + .{ "gov.ma", {} }, + .{ "net.ma", {} }, + .{ "org.ma", {} }, + .{ "press.ma", {} }, + .{ "mc", {} }, + .{ "asso.mc", {} }, + .{ "tm.mc", {} }, + .{ "md", {} }, + .{ "me", {} }, + .{ "ac.me", {} }, + .{ "co.me", {} }, + .{ "edu.me", {} }, + .{ "gov.me", {} }, + .{ "its.me", {} }, + .{ "net.me", {} }, + .{ "org.me", {} }, + .{ "priv.me", {} }, + .{ "mg", {} }, + .{ "co.mg", {} }, + .{ "com.mg", {} }, + .{ "edu.mg", {} }, + .{ "gov.mg", {} }, + .{ "mil.mg", {} }, + .{ "nom.mg", {} }, + .{ "org.mg", {} }, + .{ "prd.mg", {} }, + .{ "mh", {} }, + .{ "mil", {} }, + .{ "mk", {} }, + .{ "com.mk", {} }, + .{ "edu.mk", {} }, + .{ "gov.mk", {} }, + .{ "inf.mk", {} }, + .{ "name.mk", {} }, + .{ "net.mk", {} }, + .{ "org.mk", {} }, + .{ "ml", {} }, + .{ "ac.ml", {} }, + .{ "art.ml", {} }, + .{ "asso.ml", {} }, + .{ "com.ml", {} }, + .{ "edu.ml", {} }, + .{ "gouv.ml", {} }, + .{ "gov.ml", {} }, + .{ "info.ml", {} }, + .{ "inst.ml", {} }, + .{ "net.ml", {} }, + .{ "org.ml", {} }, + .{ "pr.ml", {} }, + .{ "presse.ml", {} }, + .{ "*.mm", {} }, + .{ "mn", {} }, + .{ "edu.mn", {} }, + .{ "gov.mn", {} }, + .{ "org.mn", {} }, + .{ "mo", {} }, + .{ "com.mo", {} }, + .{ "edu.mo", {} }, + .{ "gov.mo", {} }, + .{ "net.mo", {} }, + .{ "org.mo", {} }, + .{ "mobi", {} }, + .{ "mp", {} }, + .{ "mq", {} }, + .{ "mr", {} }, + .{ "gov.mr", {} }, + .{ "ms", {} }, + .{ "com.ms", {} }, + .{ "edu.ms", {} }, + .{ "gov.ms", {} }, + .{ "net.ms", {} }, + .{ "org.ms", {} }, + .{ "mt", {} }, + .{ "com.mt", {} }, + .{ "edu.mt", {} }, + .{ "net.mt", {} }, + .{ "org.mt", {} }, + .{ "mu", {} }, + .{ "ac.mu", {} }, + .{ "co.mu", {} }, + .{ "com.mu", {} }, + .{ "gov.mu", {} }, + .{ "net.mu", {} }, + .{ "or.mu", {} }, + .{ "org.mu", {} }, + .{ "museum", {} }, + .{ "mv", {} }, + .{ "aero.mv", {} }, + .{ "biz.mv", {} }, + .{ "com.mv", {} }, + .{ "coop.mv", {} }, + .{ "edu.mv", {} }, + .{ "gov.mv", {} }, + .{ "info.mv", {} }, + .{ "int.mv", {} }, + .{ "mil.mv", {} }, + .{ "museum.mv", {} }, + .{ "name.mv", {} }, + .{ "net.mv", {} }, + .{ "org.mv", {} }, + .{ "pro.mv", {} }, + .{ "mw", {} }, + .{ "ac.mw", {} }, + .{ "biz.mw", {} }, + .{ "co.mw", {} }, + .{ "com.mw", {} }, + .{ "coop.mw", {} }, + .{ "edu.mw", {} }, + .{ "gov.mw", {} }, + .{ "int.mw", {} }, + .{ "net.mw", {} }, + .{ "org.mw", {} }, + .{ "mx", {} }, + .{ "com.mx", {} }, + .{ "edu.mx", {} }, + .{ "gob.mx", {} }, + .{ "net.mx", {} }, + .{ "org.mx", {} }, + .{ "my", {} }, + .{ "biz.my", {} }, + .{ "com.my", {} }, + .{ "edu.my", {} }, + .{ "gov.my", {} }, + .{ "mil.my", {} }, + .{ "name.my", {} }, + .{ "net.my", {} }, + .{ "org.my", {} }, + .{ "mz", {} }, + .{ "ac.mz", {} }, + .{ "adv.mz", {} }, + .{ "co.mz", {} }, + .{ "edu.mz", {} }, + .{ "gov.mz", {} }, + .{ "mil.mz", {} }, + .{ "net.mz", {} }, + .{ "org.mz", {} }, + .{ "na", {} }, + .{ "alt.na", {} }, + .{ "co.na", {} }, + .{ "com.na", {} }, + .{ "gov.na", {} }, + .{ "net.na", {} }, + .{ "org.na", {} }, + .{ "name", {} }, + .{ "nc", {} }, + .{ "asso.nc", {} }, + .{ "nom.nc", {} }, + .{ "ne", {} }, + .{ "net", {} }, + .{ "nf", {} }, + .{ "arts.nf", {} }, + .{ "com.nf", {} }, + .{ "firm.nf", {} }, + .{ "info.nf", {} }, + .{ "net.nf", {} }, + .{ "other.nf", {} }, + .{ "per.nf", {} }, + .{ "rec.nf", {} }, + .{ "store.nf", {} }, + .{ "web.nf", {} }, + .{ "ng", {} }, + .{ "com.ng", {} }, + .{ "edu.ng", {} }, + .{ "gov.ng", {} }, + .{ "i.ng", {} }, + .{ "mil.ng", {} }, + .{ "mobi.ng", {} }, + .{ "name.ng", {} }, + .{ "net.ng", {} }, + .{ "org.ng", {} }, + .{ "sch.ng", {} }, + .{ "ni", {} }, + .{ "ac.ni", {} }, + .{ "biz.ni", {} }, + .{ "co.ni", {} }, + .{ "com.ni", {} }, + .{ "edu.ni", {} }, + .{ "gob.ni", {} }, + .{ "in.ni", {} }, + .{ "info.ni", {} }, + .{ "int.ni", {} }, + .{ "mil.ni", {} }, + .{ "net.ni", {} }, + .{ "nom.ni", {} }, + .{ "org.ni", {} }, + .{ "web.ni", {} }, + .{ "nl", {} }, + .{ "no", {} }, + .{ "fhs.no", {} }, + .{ "folkebibl.no", {} }, + .{ "fylkesbibl.no", {} }, + .{ "idrett.no", {} }, + .{ "museum.no", {} }, + .{ "priv.no", {} }, + .{ "vgs.no", {} }, + .{ "dep.no", {} }, + .{ "herad.no", {} }, + .{ "kommune.no", {} }, + .{ "mil.no", {} }, + .{ "stat.no", {} }, + .{ "aa.no", {} }, + .{ "ah.no", {} }, + .{ "bu.no", {} }, + .{ "fm.no", {} }, + .{ "hl.no", {} }, + .{ "hm.no", {} }, + .{ "jan-mayen.no", {} }, + .{ "mr.no", {} }, + .{ "nl.no", {} }, + .{ "nt.no", {} }, + .{ "of.no", {} }, + .{ "ol.no", {} }, + .{ "oslo.no", {} }, + .{ "rl.no", {} }, + .{ "sf.no", {} }, + .{ "st.no", {} }, + .{ "svalbard.no", {} }, + .{ "tm.no", {} }, + .{ "tr.no", {} }, + .{ "va.no", {} }, + .{ "vf.no", {} }, + .{ "gs.aa.no", {} }, + .{ "gs.ah.no", {} }, + .{ "gs.bu.no", {} }, + .{ "gs.fm.no", {} }, + .{ "gs.hl.no", {} }, + .{ "gs.hm.no", {} }, + .{ "gs.jan-mayen.no", {} }, + .{ "gs.mr.no", {} }, + .{ "gs.nl.no", {} }, + .{ "gs.nt.no", {} }, + .{ "gs.of.no", {} }, + .{ "gs.ol.no", {} }, + .{ "gs.oslo.no", {} }, + .{ "gs.rl.no", {} }, + .{ "gs.sf.no", {} }, + .{ "gs.st.no", {} }, + .{ "gs.svalbard.no", {} }, + .{ "gs.tm.no", {} }, + .{ "gs.tr.no", {} }, + .{ "gs.va.no", {} }, + .{ "gs.vf.no", {} }, + .{ "akrehamn.no", {} }, + .{ "åkrehamn.no", {} }, + .{ "algard.no", {} }, + .{ "ålgård.no", {} }, + .{ "arna.no", {} }, + .{ "bronnoysund.no", {} }, + .{ "brønnøysund.no", {} }, + .{ "brumunddal.no", {} }, + .{ "bryne.no", {} }, + .{ "drobak.no", {} }, + .{ "drøbak.no", {} }, + .{ "egersund.no", {} }, + .{ "fetsund.no", {} }, + .{ "floro.no", {} }, + .{ "florø.no", {} }, + .{ "fredrikstad.no", {} }, + .{ "hokksund.no", {} }, + .{ "honefoss.no", {} }, + .{ "hønefoss.no", {} }, + .{ "jessheim.no", {} }, + .{ "jorpeland.no", {} }, + .{ "jørpeland.no", {} }, + .{ "kirkenes.no", {} }, + .{ "kopervik.no", {} }, + .{ "krokstadelva.no", {} }, + .{ "langevag.no", {} }, + .{ "langevåg.no", {} }, + .{ "leirvik.no", {} }, + .{ "mjondalen.no", {} }, + .{ "mjøndalen.no", {} }, + .{ "mo-i-rana.no", {} }, + .{ "mosjoen.no", {} }, + .{ "mosjøen.no", {} }, + .{ "nesoddtangen.no", {} }, + .{ "orkanger.no", {} }, + .{ "osoyro.no", {} }, + .{ "osøyro.no", {} }, + .{ "raholt.no", {} }, + .{ "råholt.no", {} }, + .{ "sandnessjoen.no", {} }, + .{ "sandnessjøen.no", {} }, + .{ "skedsmokorset.no", {} }, + .{ "slattum.no", {} }, + .{ "spjelkavik.no", {} }, + .{ "stathelle.no", {} }, + .{ "stavern.no", {} }, + .{ "stjordalshalsen.no", {} }, + .{ "stjørdalshalsen.no", {} }, + .{ "tananger.no", {} }, + .{ "tranby.no", {} }, + .{ "vossevangen.no", {} }, + .{ "aarborte.no", {} }, + .{ "aejrie.no", {} }, + .{ "afjord.no", {} }, + .{ "åfjord.no", {} }, + .{ "agdenes.no", {} }, + .{ "nes.akershus.no", {} }, + .{ "aknoluokta.no", {} }, + .{ "ákŋoluokta.no", {} }, + .{ "al.no", {} }, + .{ "ål.no", {} }, + .{ "alaheadju.no", {} }, + .{ "álaheadju.no", {} }, + .{ "alesund.no", {} }, + .{ "ålesund.no", {} }, + .{ "alstahaug.no", {} }, + .{ "alta.no", {} }, + .{ "áltá.no", {} }, + .{ "alvdal.no", {} }, + .{ "amli.no", {} }, + .{ "åmli.no", {} }, + .{ "amot.no", {} }, + .{ "åmot.no", {} }, + .{ "andasuolo.no", {} }, + .{ "andebu.no", {} }, + .{ "andoy.no", {} }, + .{ "andøy.no", {} }, + .{ "ardal.no", {} }, + .{ "årdal.no", {} }, + .{ "aremark.no", {} }, + .{ "arendal.no", {} }, + .{ "ås.no", {} }, + .{ "aseral.no", {} }, + .{ "åseral.no", {} }, + .{ "asker.no", {} }, + .{ "askim.no", {} }, + .{ "askoy.no", {} }, + .{ "askøy.no", {} }, + .{ "askvoll.no", {} }, + .{ "asnes.no", {} }, + .{ "åsnes.no", {} }, + .{ "audnedaln.no", {} }, + .{ "aukra.no", {} }, + .{ "aure.no", {} }, + .{ "aurland.no", {} }, + .{ "aurskog-holand.no", {} }, + .{ "aurskog-høland.no", {} }, + .{ "austevoll.no", {} }, + .{ "austrheim.no", {} }, + .{ "averoy.no", {} }, + .{ "averøy.no", {} }, + .{ "badaddja.no", {} }, + .{ "bådåddjå.no", {} }, + .{ "bærum.no", {} }, + .{ "bahcavuotna.no", {} }, + .{ "báhcavuotna.no", {} }, + .{ "bahccavuotna.no", {} }, + .{ "báhccavuotna.no", {} }, + .{ "baidar.no", {} }, + .{ "báidár.no", {} }, + .{ "bajddar.no", {} }, + .{ "bájddar.no", {} }, + .{ "balat.no", {} }, + .{ "bálát.no", {} }, + .{ "balestrand.no", {} }, + .{ "ballangen.no", {} }, + .{ "balsfjord.no", {} }, + .{ "bamble.no", {} }, + .{ "bardu.no", {} }, + .{ "barum.no", {} }, + .{ "batsfjord.no", {} }, + .{ "båtsfjord.no", {} }, + .{ "bearalvahki.no", {} }, + .{ "bearalváhki.no", {} }, + .{ "beardu.no", {} }, + .{ "beiarn.no", {} }, + .{ "berg.no", {} }, + .{ "bergen.no", {} }, + .{ "berlevag.no", {} }, + .{ "berlevåg.no", {} }, + .{ "bievat.no", {} }, + .{ "bievát.no", {} }, + .{ "bindal.no", {} }, + .{ "birkenes.no", {} }, + .{ "bjarkoy.no", {} }, + .{ "bjarkøy.no", {} }, + .{ "bjerkreim.no", {} }, + .{ "bjugn.no", {} }, + .{ "bodo.no", {} }, + .{ "bodø.no", {} }, + .{ "bokn.no", {} }, + .{ "bomlo.no", {} }, + .{ "bømlo.no", {} }, + .{ "bremanger.no", {} }, + .{ "bronnoy.no", {} }, + .{ "brønnøy.no", {} }, + .{ "budejju.no", {} }, + .{ "nes.buskerud.no", {} }, + .{ "bygland.no", {} }, + .{ "bykle.no", {} }, + .{ "cahcesuolo.no", {} }, + .{ "čáhcesuolo.no", {} }, + .{ "davvenjarga.no", {} }, + .{ "davvenjárga.no", {} }, + .{ "davvesiida.no", {} }, + .{ "deatnu.no", {} }, + .{ "dielddanuorri.no", {} }, + .{ "divtasvuodna.no", {} }, + .{ "divttasvuotna.no", {} }, + .{ "donna.no", {} }, + .{ "dønna.no", {} }, + .{ "dovre.no", {} }, + .{ "drammen.no", {} }, + .{ "drangedal.no", {} }, + .{ "dyroy.no", {} }, + .{ "dyrøy.no", {} }, + .{ "eid.no", {} }, + .{ "eidfjord.no", {} }, + .{ "eidsberg.no", {} }, + .{ "eidskog.no", {} }, + .{ "eidsvoll.no", {} }, + .{ "eigersund.no", {} }, + .{ "elverum.no", {} }, + .{ "enebakk.no", {} }, + .{ "engerdal.no", {} }, + .{ "etne.no", {} }, + .{ "etnedal.no", {} }, + .{ "evenassi.no", {} }, + .{ "evenášši.no", {} }, + .{ "evenes.no", {} }, + .{ "evje-og-hornnes.no", {} }, + .{ "farsund.no", {} }, + .{ "fauske.no", {} }, + .{ "fedje.no", {} }, + .{ "fet.no", {} }, + .{ "finnoy.no", {} }, + .{ "finnøy.no", {} }, + .{ "fitjar.no", {} }, + .{ "fjaler.no", {} }, + .{ "fjell.no", {} }, + .{ "fla.no", {} }, + .{ "flå.no", {} }, + .{ "flakstad.no", {} }, + .{ "flatanger.no", {} }, + .{ "flekkefjord.no", {} }, + .{ "flesberg.no", {} }, + .{ "flora.no", {} }, + .{ "folldal.no", {} }, + .{ "forde.no", {} }, + .{ "førde.no", {} }, + .{ "forsand.no", {} }, + .{ "fosnes.no", {} }, + .{ "fræna.no", {} }, + .{ "frana.no", {} }, + .{ "frei.no", {} }, + .{ "frogn.no", {} }, + .{ "froland.no", {} }, + .{ "frosta.no", {} }, + .{ "froya.no", {} }, + .{ "frøya.no", {} }, + .{ "fuoisku.no", {} }, + .{ "fuossko.no", {} }, + .{ "fusa.no", {} }, + .{ "fyresdal.no", {} }, + .{ "gaivuotna.no", {} }, + .{ "gáivuotna.no", {} }, + .{ "galsa.no", {} }, + .{ "gálsá.no", {} }, + .{ "gamvik.no", {} }, + .{ "gangaviika.no", {} }, + .{ "gáŋgaviika.no", {} }, + .{ "gaular.no", {} }, + .{ "gausdal.no", {} }, + .{ "giehtavuoatna.no", {} }, + .{ "gildeskal.no", {} }, + .{ "gildeskål.no", {} }, + .{ "giske.no", {} }, + .{ "gjemnes.no", {} }, + .{ "gjerdrum.no", {} }, + .{ "gjerstad.no", {} }, + .{ "gjesdal.no", {} }, + .{ "gjovik.no", {} }, + .{ "gjøvik.no", {} }, + .{ "gloppen.no", {} }, + .{ "gol.no", {} }, + .{ "gran.no", {} }, + .{ "grane.no", {} }, + .{ "granvin.no", {} }, + .{ "gratangen.no", {} }, + .{ "grimstad.no", {} }, + .{ "grong.no", {} }, + .{ "grue.no", {} }, + .{ "gulen.no", {} }, + .{ "guovdageaidnu.no", {} }, + .{ "ha.no", {} }, + .{ "hå.no", {} }, + .{ "habmer.no", {} }, + .{ "hábmer.no", {} }, + .{ "hadsel.no", {} }, + .{ "hægebostad.no", {} }, + .{ "hagebostad.no", {} }, + .{ "halden.no", {} }, + .{ "halsa.no", {} }, + .{ "hamar.no", {} }, + .{ "hamaroy.no", {} }, + .{ "hammarfeasta.no", {} }, + .{ "hámmárfeasta.no", {} }, + .{ "hammerfest.no", {} }, + .{ "hapmir.no", {} }, + .{ "hápmir.no", {} }, + .{ "haram.no", {} }, + .{ "hareid.no", {} }, + .{ "harstad.no", {} }, + .{ "hasvik.no", {} }, + .{ "hattfjelldal.no", {} }, + .{ "haugesund.no", {} }, + .{ "os.hedmark.no", {} }, + .{ "valer.hedmark.no", {} }, + .{ "våler.hedmark.no", {} }, + .{ "hemne.no", {} }, + .{ "hemnes.no", {} }, + .{ "hemsedal.no", {} }, + .{ "hitra.no", {} }, + .{ "hjartdal.no", {} }, + .{ "hjelmeland.no", {} }, + .{ "hobol.no", {} }, + .{ "hobøl.no", {} }, + .{ "hof.no", {} }, + .{ "hol.no", {} }, + .{ "hole.no", {} }, + .{ "holmestrand.no", {} }, + .{ "holtalen.no", {} }, + .{ "holtålen.no", {} }, + .{ "os.hordaland.no", {} }, + .{ "hornindal.no", {} }, + .{ "horten.no", {} }, + .{ "hoyanger.no", {} }, + .{ "høyanger.no", {} }, + .{ "hoylandet.no", {} }, + .{ "høylandet.no", {} }, + .{ "hurdal.no", {} }, + .{ "hurum.no", {} }, + .{ "hvaler.no", {} }, + .{ "hyllestad.no", {} }, + .{ "ibestad.no", {} }, + .{ "inderoy.no", {} }, + .{ "inderøy.no", {} }, + .{ "iveland.no", {} }, + .{ "ivgu.no", {} }, + .{ "jevnaker.no", {} }, + .{ "jolster.no", {} }, + .{ "jølster.no", {} }, + .{ "jondal.no", {} }, + .{ "kafjord.no", {} }, + .{ "kåfjord.no", {} }, + .{ "karasjohka.no", {} }, + .{ "kárášjohka.no", {} }, + .{ "karasjok.no", {} }, + .{ "karlsoy.no", {} }, + .{ "karmoy.no", {} }, + .{ "karmøy.no", {} }, + .{ "kautokeino.no", {} }, + .{ "klabu.no", {} }, + .{ "klæbu.no", {} }, + .{ "klepp.no", {} }, + .{ "kongsberg.no", {} }, + .{ "kongsvinger.no", {} }, + .{ "kraanghke.no", {} }, + .{ "kråanghke.no", {} }, + .{ "kragero.no", {} }, + .{ "kragerø.no", {} }, + .{ "kristiansand.no", {} }, + .{ "kristiansund.no", {} }, + .{ "krodsherad.no", {} }, + .{ "krødsherad.no", {} }, + .{ "kvæfjord.no", {} }, + .{ "kvænangen.no", {} }, + .{ "kvafjord.no", {} }, + .{ "kvalsund.no", {} }, + .{ "kvam.no", {} }, + .{ "kvanangen.no", {} }, + .{ "kvinesdal.no", {} }, + .{ "kvinnherad.no", {} }, + .{ "kviteseid.no", {} }, + .{ "kvitsoy.no", {} }, + .{ "kvitsøy.no", {} }, + .{ "laakesvuemie.no", {} }, + .{ "lærdal.no", {} }, + .{ "lahppi.no", {} }, + .{ "láhppi.no", {} }, + .{ "lardal.no", {} }, + .{ "larvik.no", {} }, + .{ "lavagis.no", {} }, + .{ "lavangen.no", {} }, + .{ "leangaviika.no", {} }, + .{ "leaŋgaviika.no", {} }, + .{ "lebesby.no", {} }, + .{ "leikanger.no", {} }, + .{ "leirfjord.no", {} }, + .{ "leka.no", {} }, + .{ "leksvik.no", {} }, + .{ "lenvik.no", {} }, + .{ "lerdal.no", {} }, + .{ "lesja.no", {} }, + .{ "levanger.no", {} }, + .{ "lier.no", {} }, + .{ "lierne.no", {} }, + .{ "lillehammer.no", {} }, + .{ "lillesand.no", {} }, + .{ "lindas.no", {} }, + .{ "lindås.no", {} }, + .{ "lindesnes.no", {} }, + .{ "loabat.no", {} }, + .{ "loabát.no", {} }, + .{ "lodingen.no", {} }, + .{ "lødingen.no", {} }, + .{ "lom.no", {} }, + .{ "loppa.no", {} }, + .{ "lorenskog.no", {} }, + .{ "lørenskog.no", {} }, + .{ "loten.no", {} }, + .{ "løten.no", {} }, + .{ "lund.no", {} }, + .{ "lunner.no", {} }, + .{ "luroy.no", {} }, + .{ "lurøy.no", {} }, + .{ "luster.no", {} }, + .{ "lyngdal.no", {} }, + .{ "lyngen.no", {} }, + .{ "malatvuopmi.no", {} }, + .{ "málatvuopmi.no", {} }, + .{ "malselv.no", {} }, + .{ "målselv.no", {} }, + .{ "malvik.no", {} }, + .{ "mandal.no", {} }, + .{ "marker.no", {} }, + .{ "marnardal.no", {} }, + .{ "masfjorden.no", {} }, + .{ "masoy.no", {} }, + .{ "måsøy.no", {} }, + .{ "matta-varjjat.no", {} }, + .{ "mátta-várjjat.no", {} }, + .{ "meland.no", {} }, + .{ "meldal.no", {} }, + .{ "melhus.no", {} }, + .{ "meloy.no", {} }, + .{ "meløy.no", {} }, + .{ "meraker.no", {} }, + .{ "meråker.no", {} }, + .{ "midsund.no", {} }, + .{ "midtre-gauldal.no", {} }, + .{ "moareke.no", {} }, + .{ "moåreke.no", {} }, + .{ "modalen.no", {} }, + .{ "modum.no", {} }, + .{ "molde.no", {} }, + .{ "heroy.more-og-romsdal.no", {} }, + .{ "sande.more-og-romsdal.no", {} }, + .{ "herøy.møre-og-romsdal.no", {} }, + .{ "sande.møre-og-romsdal.no", {} }, + .{ "moskenes.no", {} }, + .{ "moss.no", {} }, + .{ "mosvik.no", {} }, + .{ "muosat.no", {} }, + .{ "muosát.no", {} }, + .{ "naamesjevuemie.no", {} }, + .{ "nååmesjevuemie.no", {} }, + .{ "nærøy.no", {} }, + .{ "namdalseid.no", {} }, + .{ "namsos.no", {} }, + .{ "namsskogan.no", {} }, + .{ "nannestad.no", {} }, + .{ "naroy.no", {} }, + .{ "narviika.no", {} }, + .{ "narvik.no", {} }, + .{ "naustdal.no", {} }, + .{ "navuotna.no", {} }, + .{ "návuotna.no", {} }, + .{ "nedre-eiker.no", {} }, + .{ "nesna.no", {} }, + .{ "nesodden.no", {} }, + .{ "nesseby.no", {} }, + .{ "nesset.no", {} }, + .{ "nissedal.no", {} }, + .{ "nittedal.no", {} }, + .{ "nord-aurdal.no", {} }, + .{ "nord-fron.no", {} }, + .{ "nord-odal.no", {} }, + .{ "norddal.no", {} }, + .{ "nordkapp.no", {} }, + .{ "bo.nordland.no", {} }, + .{ "bø.nordland.no", {} }, + .{ "heroy.nordland.no", {} }, + .{ "herøy.nordland.no", {} }, + .{ "nordre-land.no", {} }, + .{ "nordreisa.no", {} }, + .{ "nore-og-uvdal.no", {} }, + .{ "notodden.no", {} }, + .{ "notteroy.no", {} }, + .{ "nøtterøy.no", {} }, + .{ "odda.no", {} }, + .{ "oksnes.no", {} }, + .{ "øksnes.no", {} }, + .{ "omasvuotna.no", {} }, + .{ "oppdal.no", {} }, + .{ "oppegard.no", {} }, + .{ "oppegård.no", {} }, + .{ "orkdal.no", {} }, + .{ "orland.no", {} }, + .{ "ørland.no", {} }, + .{ "orskog.no", {} }, + .{ "ørskog.no", {} }, + .{ "orsta.no", {} }, + .{ "ørsta.no", {} }, + .{ "osen.no", {} }, + .{ "osteroy.no", {} }, + .{ "osterøy.no", {} }, + .{ "valer.ostfold.no", {} }, + .{ "våler.østfold.no", {} }, + .{ "ostre-toten.no", {} }, + .{ "østre-toten.no", {} }, + .{ "overhalla.no", {} }, + .{ "ovre-eiker.no", {} }, + .{ "øvre-eiker.no", {} }, + .{ "oyer.no", {} }, + .{ "øyer.no", {} }, + .{ "oygarden.no", {} }, + .{ "øygarden.no", {} }, + .{ "oystre-slidre.no", {} }, + .{ "øystre-slidre.no", {} }, + .{ "porsanger.no", {} }, + .{ "porsangu.no", {} }, + .{ "porsáŋgu.no", {} }, + .{ "porsgrunn.no", {} }, + .{ "rade.no", {} }, + .{ "råde.no", {} }, + .{ "radoy.no", {} }, + .{ "radøy.no", {} }, + .{ "rælingen.no", {} }, + .{ "rahkkeravju.no", {} }, + .{ "ráhkkerávju.no", {} }, + .{ "raisa.no", {} }, + .{ "ráisa.no", {} }, + .{ "rakkestad.no", {} }, + .{ "ralingen.no", {} }, + .{ "rana.no", {} }, + .{ "randaberg.no", {} }, + .{ "rauma.no", {} }, + .{ "rendalen.no", {} }, + .{ "rennebu.no", {} }, + .{ "rennesoy.no", {} }, + .{ "rennesøy.no", {} }, + .{ "rindal.no", {} }, + .{ "ringebu.no", {} }, + .{ "ringerike.no", {} }, + .{ "ringsaker.no", {} }, + .{ "risor.no", {} }, + .{ "risør.no", {} }, + .{ "rissa.no", {} }, + .{ "roan.no", {} }, + .{ "rodoy.no", {} }, + .{ "rødøy.no", {} }, + .{ "rollag.no", {} }, + .{ "romsa.no", {} }, + .{ "romskog.no", {} }, + .{ "rømskog.no", {} }, + .{ "roros.no", {} }, + .{ "røros.no", {} }, + .{ "rost.no", {} }, + .{ "røst.no", {} }, + .{ "royken.no", {} }, + .{ "røyken.no", {} }, + .{ "royrvik.no", {} }, + .{ "røyrvik.no", {} }, + .{ "ruovat.no", {} }, + .{ "rygge.no", {} }, + .{ "salangen.no", {} }, + .{ "salat.no", {} }, + .{ "sálat.no", {} }, + .{ "sálát.no", {} }, + .{ "saltdal.no", {} }, + .{ "samnanger.no", {} }, + .{ "sandefjord.no", {} }, + .{ "sandnes.no", {} }, + .{ "sandoy.no", {} }, + .{ "sandøy.no", {} }, + .{ "sarpsborg.no", {} }, + .{ "sauda.no", {} }, + .{ "sauherad.no", {} }, + .{ "sel.no", {} }, + .{ "selbu.no", {} }, + .{ "selje.no", {} }, + .{ "seljord.no", {} }, + .{ "siellak.no", {} }, + .{ "sigdal.no", {} }, + .{ "siljan.no", {} }, + .{ "sirdal.no", {} }, + .{ "skanit.no", {} }, + .{ "skánit.no", {} }, + .{ "skanland.no", {} }, + .{ "skånland.no", {} }, + .{ "skaun.no", {} }, + .{ "skedsmo.no", {} }, + .{ "ski.no", {} }, + .{ "skien.no", {} }, + .{ "skierva.no", {} }, + .{ "skiervá.no", {} }, + .{ "skiptvet.no", {} }, + .{ "skjak.no", {} }, + .{ "skjåk.no", {} }, + .{ "skjervoy.no", {} }, + .{ "skjervøy.no", {} }, + .{ "skodje.no", {} }, + .{ "smola.no", {} }, + .{ "smøla.no", {} }, + .{ "snaase.no", {} }, + .{ "snåase.no", {} }, + .{ "snasa.no", {} }, + .{ "snåsa.no", {} }, + .{ "snillfjord.no", {} }, + .{ "snoasa.no", {} }, + .{ "sogndal.no", {} }, + .{ "sogne.no", {} }, + .{ "søgne.no", {} }, + .{ "sokndal.no", {} }, + .{ "sola.no", {} }, + .{ "solund.no", {} }, + .{ "somna.no", {} }, + .{ "sømna.no", {} }, + .{ "sondre-land.no", {} }, + .{ "søndre-land.no", {} }, + .{ "songdalen.no", {} }, + .{ "sor-aurdal.no", {} }, + .{ "sør-aurdal.no", {} }, + .{ "sor-fron.no", {} }, + .{ "sør-fron.no", {} }, + .{ "sor-odal.no", {} }, + .{ "sør-odal.no", {} }, + .{ "sor-varanger.no", {} }, + .{ "sør-varanger.no", {} }, + .{ "sorfold.no", {} }, + .{ "sørfold.no", {} }, + .{ "sorreisa.no", {} }, + .{ "sørreisa.no", {} }, + .{ "sortland.no", {} }, + .{ "sorum.no", {} }, + .{ "sørum.no", {} }, + .{ "spydeberg.no", {} }, + .{ "stange.no", {} }, + .{ "stavanger.no", {} }, + .{ "steigen.no", {} }, + .{ "steinkjer.no", {} }, + .{ "stjordal.no", {} }, + .{ "stjørdal.no", {} }, + .{ "stokke.no", {} }, + .{ "stor-elvdal.no", {} }, + .{ "stord.no", {} }, + .{ "stordal.no", {} }, + .{ "storfjord.no", {} }, + .{ "strand.no", {} }, + .{ "stranda.no", {} }, + .{ "stryn.no", {} }, + .{ "sula.no", {} }, + .{ "suldal.no", {} }, + .{ "sund.no", {} }, + .{ "sunndal.no", {} }, + .{ "surnadal.no", {} }, + .{ "sveio.no", {} }, + .{ "svelvik.no", {} }, + .{ "sykkylven.no", {} }, + .{ "tana.no", {} }, + .{ "bo.telemark.no", {} }, + .{ "bø.telemark.no", {} }, + .{ "time.no", {} }, + .{ "tingvoll.no", {} }, + .{ "tinn.no", {} }, + .{ "tjeldsund.no", {} }, + .{ "tjome.no", {} }, + .{ "tjøme.no", {} }, + .{ "tokke.no", {} }, + .{ "tolga.no", {} }, + .{ "tonsberg.no", {} }, + .{ "tønsberg.no", {} }, + .{ "torsken.no", {} }, + .{ "træna.no", {} }, + .{ "trana.no", {} }, + .{ "tranoy.no", {} }, + .{ "tranøy.no", {} }, + .{ "troandin.no", {} }, + .{ "trogstad.no", {} }, + .{ "trøgstad.no", {} }, + .{ "tromsa.no", {} }, + .{ "tromso.no", {} }, + .{ "tromsø.no", {} }, + .{ "trondheim.no", {} }, + .{ "trysil.no", {} }, + .{ "tvedestrand.no", {} }, + .{ "tydal.no", {} }, + .{ "tynset.no", {} }, + .{ "tysfjord.no", {} }, + .{ "tysnes.no", {} }, + .{ "tysvær.no", {} }, + .{ "tysvar.no", {} }, + .{ "ullensaker.no", {} }, + .{ "ullensvang.no", {} }, + .{ "ulvik.no", {} }, + .{ "unjarga.no", {} }, + .{ "unjárga.no", {} }, + .{ "utsira.no", {} }, + .{ "vaapste.no", {} }, + .{ "vadso.no", {} }, + .{ "vadsø.no", {} }, + .{ "værøy.no", {} }, + .{ "vaga.no", {} }, + .{ "vågå.no", {} }, + .{ "vagan.no", {} }, + .{ "vågan.no", {} }, + .{ "vagsoy.no", {} }, + .{ "vågsøy.no", {} }, + .{ "vaksdal.no", {} }, + .{ "valle.no", {} }, + .{ "vang.no", {} }, + .{ "vanylven.no", {} }, + .{ "vardo.no", {} }, + .{ "vardø.no", {} }, + .{ "varggat.no", {} }, + .{ "várggát.no", {} }, + .{ "varoy.no", {} }, + .{ "vefsn.no", {} }, + .{ "vega.no", {} }, + .{ "vegarshei.no", {} }, + .{ "vegårshei.no", {} }, + .{ "vennesla.no", {} }, + .{ "verdal.no", {} }, + .{ "verran.no", {} }, + .{ "vestby.no", {} }, + .{ "sande.vestfold.no", {} }, + .{ "vestnes.no", {} }, + .{ "vestre-slidre.no", {} }, + .{ "vestre-toten.no", {} }, + .{ "vestvagoy.no", {} }, + .{ "vestvågøy.no", {} }, + .{ "vevelstad.no", {} }, + .{ "vik.no", {} }, + .{ "vikna.no", {} }, + .{ "vindafjord.no", {} }, + .{ "voagat.no", {} }, + .{ "volda.no", {} }, + .{ "voss.no", {} }, + .{ "*.np", {} }, + .{ "nr", {} }, + .{ "biz.nr", {} }, + .{ "com.nr", {} }, + .{ "edu.nr", {} }, + .{ "gov.nr", {} }, + .{ "info.nr", {} }, + .{ "net.nr", {} }, + .{ "org.nr", {} }, + .{ "nu", {} }, + .{ "nz", {} }, + .{ "ac.nz", {} }, + .{ "co.nz", {} }, + .{ "cri.nz", {} }, + .{ "geek.nz", {} }, + .{ "gen.nz", {} }, + .{ "govt.nz", {} }, + .{ "health.nz", {} }, + .{ "iwi.nz", {} }, + .{ "kiwi.nz", {} }, + .{ "maori.nz", {} }, + .{ "māori.nz", {} }, + .{ "mil.nz", {} }, + .{ "net.nz", {} }, + .{ "org.nz", {} }, + .{ "parliament.nz", {} }, + .{ "school.nz", {} }, + .{ "om", {} }, + .{ "co.om", {} }, + .{ "com.om", {} }, + .{ "edu.om", {} }, + .{ "gov.om", {} }, + .{ "med.om", {} }, + .{ "museum.om", {} }, + .{ "net.om", {} }, + .{ "org.om", {} }, + .{ "pro.om", {} }, + .{ "onion", {} }, + .{ "org", {} }, + .{ "pa", {} }, + .{ "abo.pa", {} }, + .{ "ac.pa", {} }, + .{ "com.pa", {} }, + .{ "edu.pa", {} }, + .{ "gob.pa", {} }, + .{ "ing.pa", {} }, + .{ "med.pa", {} }, + .{ "net.pa", {} }, + .{ "nom.pa", {} }, + .{ "org.pa", {} }, + .{ "sld.pa", {} }, + .{ "pe", {} }, + .{ "com.pe", {} }, + .{ "edu.pe", {} }, + .{ "gob.pe", {} }, + .{ "mil.pe", {} }, + .{ "net.pe", {} }, + .{ "nom.pe", {} }, + .{ "org.pe", {} }, + .{ "pf", {} }, + .{ "com.pf", {} }, + .{ "edu.pf", {} }, + .{ "org.pf", {} }, + .{ "*.pg", {} }, + .{ "ph", {} }, + .{ "com.ph", {} }, + .{ "edu.ph", {} }, + .{ "gov.ph", {} }, + .{ "i.ph", {} }, + .{ "mil.ph", {} }, + .{ "net.ph", {} }, + .{ "ngo.ph", {} }, + .{ "org.ph", {} }, + .{ "pk", {} }, + .{ "ac.pk", {} }, + .{ "biz.pk", {} }, + .{ "com.pk", {} }, + .{ "edu.pk", {} }, + .{ "fam.pk", {} }, + .{ "gkp.pk", {} }, + .{ "gob.pk", {} }, + .{ "gog.pk", {} }, + .{ "gok.pk", {} }, + .{ "gop.pk", {} }, + .{ "gos.pk", {} }, + .{ "gov.pk", {} }, + .{ "net.pk", {} }, + .{ "org.pk", {} }, + .{ "web.pk", {} }, + .{ "pl", {} }, + .{ "com.pl", {} }, + .{ "net.pl", {} }, + .{ "org.pl", {} }, + .{ "agro.pl", {} }, + .{ "aid.pl", {} }, + .{ "atm.pl", {} }, + .{ "auto.pl", {} }, + .{ "biz.pl", {} }, + .{ "edu.pl", {} }, + .{ "gmina.pl", {} }, + .{ "gsm.pl", {} }, + .{ "info.pl", {} }, + .{ "mail.pl", {} }, + .{ "media.pl", {} }, + .{ "miasta.pl", {} }, + .{ "mil.pl", {} }, + .{ "nieruchomosci.pl", {} }, + .{ "nom.pl", {} }, + .{ "pc.pl", {} }, + .{ "powiat.pl", {} }, + .{ "priv.pl", {} }, + .{ "realestate.pl", {} }, + .{ "rel.pl", {} }, + .{ "sex.pl", {} }, + .{ "shop.pl", {} }, + .{ "sklep.pl", {} }, + .{ "sos.pl", {} }, + .{ "szkola.pl", {} }, + .{ "targi.pl", {} }, + .{ "tm.pl", {} }, + .{ "tourism.pl", {} }, + .{ "travel.pl", {} }, + .{ "turystyka.pl", {} }, + .{ "gov.pl", {} }, + .{ "ap.gov.pl", {} }, + .{ "griw.gov.pl", {} }, + .{ "ic.gov.pl", {} }, + .{ "is.gov.pl", {} }, + .{ "kmpsp.gov.pl", {} }, + .{ "konsulat.gov.pl", {} }, + .{ "kppsp.gov.pl", {} }, + .{ "kwp.gov.pl", {} }, + .{ "kwpsp.gov.pl", {} }, + .{ "mup.gov.pl", {} }, + .{ "mw.gov.pl", {} }, + .{ "oia.gov.pl", {} }, + .{ "oirm.gov.pl", {} }, + .{ "oke.gov.pl", {} }, + .{ "oow.gov.pl", {} }, + .{ "oschr.gov.pl", {} }, + .{ "oum.gov.pl", {} }, + .{ "pa.gov.pl", {} }, + .{ "pinb.gov.pl", {} }, + .{ "piw.gov.pl", {} }, + .{ "po.gov.pl", {} }, + .{ "pr.gov.pl", {} }, + .{ "psp.gov.pl", {} }, + .{ "psse.gov.pl", {} }, + .{ "pup.gov.pl", {} }, + .{ "rzgw.gov.pl", {} }, + .{ "sa.gov.pl", {} }, + .{ "sdn.gov.pl", {} }, + .{ "sko.gov.pl", {} }, + .{ "so.gov.pl", {} }, + .{ "sr.gov.pl", {} }, + .{ "starostwo.gov.pl", {} }, + .{ "ug.gov.pl", {} }, + .{ "ugim.gov.pl", {} }, + .{ "um.gov.pl", {} }, + .{ "umig.gov.pl", {} }, + .{ "upow.gov.pl", {} }, + .{ "uppo.gov.pl", {} }, + .{ "us.gov.pl", {} }, + .{ "uw.gov.pl", {} }, + .{ "uzs.gov.pl", {} }, + .{ "wif.gov.pl", {} }, + .{ "wiih.gov.pl", {} }, + .{ "winb.gov.pl", {} }, + .{ "wios.gov.pl", {} }, + .{ "witd.gov.pl", {} }, + .{ "wiw.gov.pl", {} }, + .{ "wkz.gov.pl", {} }, + .{ "wsa.gov.pl", {} }, + .{ "wskr.gov.pl", {} }, + .{ "wsse.gov.pl", {} }, + .{ "wuoz.gov.pl", {} }, + .{ "wzmiuw.gov.pl", {} }, + .{ "zp.gov.pl", {} }, + .{ "zpisdn.gov.pl", {} }, + .{ "augustow.pl", {} }, + .{ "babia-gora.pl", {} }, + .{ "bedzin.pl", {} }, + .{ "beskidy.pl", {} }, + .{ "bialowieza.pl", {} }, + .{ "bialystok.pl", {} }, + .{ "bielawa.pl", {} }, + .{ "bieszczady.pl", {} }, + .{ "boleslawiec.pl", {} }, + .{ "bydgoszcz.pl", {} }, + .{ "bytom.pl", {} }, + .{ "cieszyn.pl", {} }, + .{ "czeladz.pl", {} }, + .{ "czest.pl", {} }, + .{ "dlugoleka.pl", {} }, + .{ "elblag.pl", {} }, + .{ "elk.pl", {} }, + .{ "glogow.pl", {} }, + .{ "gniezno.pl", {} }, + .{ "gorlice.pl", {} }, + .{ "grajewo.pl", {} }, + .{ "ilawa.pl", {} }, + .{ "jaworzno.pl", {} }, + .{ "jelenia-gora.pl", {} }, + .{ "jgora.pl", {} }, + .{ "kalisz.pl", {} }, + .{ "karpacz.pl", {} }, + .{ "kartuzy.pl", {} }, + .{ "kaszuby.pl", {} }, + .{ "katowice.pl", {} }, + .{ "kazimierz-dolny.pl", {} }, + .{ "kepno.pl", {} }, + .{ "ketrzyn.pl", {} }, + .{ "klodzko.pl", {} }, + .{ "kobierzyce.pl", {} }, + .{ "kolobrzeg.pl", {} }, + .{ "konin.pl", {} }, + .{ "konskowola.pl", {} }, + .{ "kutno.pl", {} }, + .{ "lapy.pl", {} }, + .{ "lebork.pl", {} }, + .{ "legnica.pl", {} }, + .{ "lezajsk.pl", {} }, + .{ "limanowa.pl", {} }, + .{ "lomza.pl", {} }, + .{ "lowicz.pl", {} }, + .{ "lubin.pl", {} }, + .{ "lukow.pl", {} }, + .{ "malbork.pl", {} }, + .{ "malopolska.pl", {} }, + .{ "mazowsze.pl", {} }, + .{ "mazury.pl", {} }, + .{ "mielec.pl", {} }, + .{ "mielno.pl", {} }, + .{ "mragowo.pl", {} }, + .{ "naklo.pl", {} }, + .{ "nowaruda.pl", {} }, + .{ "nysa.pl", {} }, + .{ "olawa.pl", {} }, + .{ "olecko.pl", {} }, + .{ "olkusz.pl", {} }, + .{ "olsztyn.pl", {} }, + .{ "opoczno.pl", {} }, + .{ "opole.pl", {} }, + .{ "ostroda.pl", {} }, + .{ "ostroleka.pl", {} }, + .{ "ostrowiec.pl", {} }, + .{ "ostrowwlkp.pl", {} }, + .{ "pila.pl", {} }, + .{ "pisz.pl", {} }, + .{ "podhale.pl", {} }, + .{ "podlasie.pl", {} }, + .{ "polkowice.pl", {} }, + .{ "pomorskie.pl", {} }, + .{ "pomorze.pl", {} }, + .{ "prochowice.pl", {} }, + .{ "pruszkow.pl", {} }, + .{ "przeworsk.pl", {} }, + .{ "pulawy.pl", {} }, + .{ "radom.pl", {} }, + .{ "rawa-maz.pl", {} }, + .{ "rybnik.pl", {} }, + .{ "rzeszow.pl", {} }, + .{ "sanok.pl", {} }, + .{ "sejny.pl", {} }, + .{ "skoczow.pl", {} }, + .{ "slask.pl", {} }, + .{ "slupsk.pl", {} }, + .{ "sosnowiec.pl", {} }, + .{ "stalowa-wola.pl", {} }, + .{ "starachowice.pl", {} }, + .{ "stargard.pl", {} }, + .{ "suwalki.pl", {} }, + .{ "swidnica.pl", {} }, + .{ "swiebodzin.pl", {} }, + .{ "swinoujscie.pl", {} }, + .{ "szczecin.pl", {} }, + .{ "szczytno.pl", {} }, + .{ "tarnobrzeg.pl", {} }, + .{ "tgory.pl", {} }, + .{ "turek.pl", {} }, + .{ "tychy.pl", {} }, + .{ "ustka.pl", {} }, + .{ "walbrzych.pl", {} }, + .{ "warmia.pl", {} }, + .{ "warszawa.pl", {} }, + .{ "waw.pl", {} }, + .{ "wegrow.pl", {} }, + .{ "wielun.pl", {} }, + .{ "wlocl.pl", {} }, + .{ "wloclawek.pl", {} }, + .{ "wodzislaw.pl", {} }, + .{ "wolomin.pl", {} }, + .{ "wroclaw.pl", {} }, + .{ "zachpomor.pl", {} }, + .{ "zagan.pl", {} }, + .{ "zarow.pl", {} }, + .{ "zgora.pl", {} }, + .{ "zgorzelec.pl", {} }, + .{ "pm", {} }, + .{ "pn", {} }, + .{ "co.pn", {} }, + .{ "edu.pn", {} }, + .{ "gov.pn", {} }, + .{ "net.pn", {} }, + .{ "org.pn", {} }, + .{ "post", {} }, + .{ "pr", {} }, + .{ "biz.pr", {} }, + .{ "com.pr", {} }, + .{ "edu.pr", {} }, + .{ "gov.pr", {} }, + .{ "info.pr", {} }, + .{ "isla.pr", {} }, + .{ "name.pr", {} }, + .{ "net.pr", {} }, + .{ "org.pr", {} }, + .{ "pro.pr", {} }, + .{ "ac.pr", {} }, + .{ "est.pr", {} }, + .{ "prof.pr", {} }, + .{ "pro", {} }, + .{ "aaa.pro", {} }, + .{ "aca.pro", {} }, + .{ "acct.pro", {} }, + .{ "avocat.pro", {} }, + .{ "bar.pro", {} }, + .{ "cpa.pro", {} }, + .{ "eng.pro", {} }, + .{ "jur.pro", {} }, + .{ "law.pro", {} }, + .{ "med.pro", {} }, + .{ "recht.pro", {} }, + .{ "ps", {} }, + .{ "com.ps", {} }, + .{ "edu.ps", {} }, + .{ "gov.ps", {} }, + .{ "net.ps", {} }, + .{ "org.ps", {} }, + .{ "plo.ps", {} }, + .{ "sec.ps", {} }, + .{ "pt", {} }, + .{ "com.pt", {} }, + .{ "edu.pt", {} }, + .{ "gov.pt", {} }, + .{ "int.pt", {} }, + .{ "net.pt", {} }, + .{ "nome.pt", {} }, + .{ "org.pt", {} }, + .{ "publ.pt", {} }, + .{ "pw", {} }, + .{ "gov.pw", {} }, + .{ "py", {} }, + .{ "com.py", {} }, + .{ "coop.py", {} }, + .{ "edu.py", {} }, + .{ "gov.py", {} }, + .{ "mil.py", {} }, + .{ "net.py", {} }, + .{ "org.py", {} }, + .{ "qa", {} }, + .{ "com.qa", {} }, + .{ "edu.qa", {} }, + .{ "gov.qa", {} }, + .{ "mil.qa", {} }, + .{ "name.qa", {} }, + .{ "net.qa", {} }, + .{ "org.qa", {} }, + .{ "sch.qa", {} }, + .{ "re", {} }, + .{ "asso.re", {} }, + .{ "com.re", {} }, + .{ "ro", {} }, + .{ "arts.ro", {} }, + .{ "com.ro", {} }, + .{ "firm.ro", {} }, + .{ "info.ro", {} }, + .{ "nom.ro", {} }, + .{ "nt.ro", {} }, + .{ "org.ro", {} }, + .{ "rec.ro", {} }, + .{ "store.ro", {} }, + .{ "tm.ro", {} }, + .{ "www.ro", {} }, + .{ "rs", {} }, + .{ "ac.rs", {} }, + .{ "co.rs", {} }, + .{ "edu.rs", {} }, + .{ "gov.rs", {} }, + .{ "in.rs", {} }, + .{ "org.rs", {} }, + .{ "ru", {} }, + .{ "rw", {} }, + .{ "ac.rw", {} }, + .{ "co.rw", {} }, + .{ "coop.rw", {} }, + .{ "gov.rw", {} }, + .{ "mil.rw", {} }, + .{ "net.rw", {} }, + .{ "org.rw", {} }, + .{ "sa", {} }, + .{ "com.sa", {} }, + .{ "edu.sa", {} }, + .{ "gov.sa", {} }, + .{ "med.sa", {} }, + .{ "net.sa", {} }, + .{ "org.sa", {} }, + .{ "pub.sa", {} }, + .{ "sch.sa", {} }, + .{ "sb", {} }, + .{ "com.sb", {} }, + .{ "edu.sb", {} }, + .{ "gov.sb", {} }, + .{ "net.sb", {} }, + .{ "org.sb", {} }, + .{ "sc", {} }, + .{ "com.sc", {} }, + .{ "edu.sc", {} }, + .{ "gov.sc", {} }, + .{ "net.sc", {} }, + .{ "org.sc", {} }, + .{ "sd", {} }, + .{ "com.sd", {} }, + .{ "edu.sd", {} }, + .{ "gov.sd", {} }, + .{ "info.sd", {} }, + .{ "med.sd", {} }, + .{ "net.sd", {} }, + .{ "org.sd", {} }, + .{ "tv.sd", {} }, + .{ "se", {} }, + .{ "a.se", {} }, + .{ "ac.se", {} }, + .{ "b.se", {} }, + .{ "bd.se", {} }, + .{ "brand.se", {} }, + .{ "c.se", {} }, + .{ "d.se", {} }, + .{ "e.se", {} }, + .{ "f.se", {} }, + .{ "fh.se", {} }, + .{ "fhsk.se", {} }, + .{ "fhv.se", {} }, + .{ "g.se", {} }, + .{ "h.se", {} }, + .{ "i.se", {} }, + .{ "k.se", {} }, + .{ "komforb.se", {} }, + .{ "kommunalforbund.se", {} }, + .{ "komvux.se", {} }, + .{ "l.se", {} }, + .{ "lanbib.se", {} }, + .{ "m.se", {} }, + .{ "n.se", {} }, + .{ "naturbruksgymn.se", {} }, + .{ "o.se", {} }, + .{ "org.se", {} }, + .{ "p.se", {} }, + .{ "parti.se", {} }, + .{ "pp.se", {} }, + .{ "press.se", {} }, + .{ "r.se", {} }, + .{ "s.se", {} }, + .{ "t.se", {} }, + .{ "tm.se", {} }, + .{ "u.se", {} }, + .{ "w.se", {} }, + .{ "x.se", {} }, + .{ "y.se", {} }, + .{ "z.se", {} }, + .{ "sg", {} }, + .{ "com.sg", {} }, + .{ "edu.sg", {} }, + .{ "gov.sg", {} }, + .{ "net.sg", {} }, + .{ "org.sg", {} }, + .{ "sh", {} }, + .{ "com.sh", {} }, + .{ "gov.sh", {} }, + .{ "mil.sh", {} }, + .{ "net.sh", {} }, + .{ "org.sh", {} }, + .{ "si", {} }, + .{ "sj", {} }, + .{ "sk", {} }, + .{ "sl", {} }, + .{ "com.sl", {} }, + .{ "edu.sl", {} }, + .{ "gov.sl", {} }, + .{ "net.sl", {} }, + .{ "org.sl", {} }, + .{ "sm", {} }, + .{ "sn", {} }, + .{ "art.sn", {} }, + .{ "com.sn", {} }, + .{ "edu.sn", {} }, + .{ "gouv.sn", {} }, + .{ "org.sn", {} }, + .{ "perso.sn", {} }, + .{ "univ.sn", {} }, + .{ "so", {} }, + .{ "com.so", {} }, + .{ "edu.so", {} }, + .{ "gov.so", {} }, + .{ "me.so", {} }, + .{ "net.so", {} }, + .{ "org.so", {} }, + .{ "sr", {} }, + .{ "ss", {} }, + .{ "biz.ss", {} }, + .{ "co.ss", {} }, + .{ "com.ss", {} }, + .{ "edu.ss", {} }, + .{ "gov.ss", {} }, + .{ "me.ss", {} }, + .{ "net.ss", {} }, + .{ "org.ss", {} }, + .{ "sch.ss", {} }, + .{ "st", {} }, + .{ "co.st", {} }, + .{ "com.st", {} }, + .{ "consulado.st", {} }, + .{ "edu.st", {} }, + .{ "embaixada.st", {} }, + .{ "mil.st", {} }, + .{ "net.st", {} }, + .{ "org.st", {} }, + .{ "principe.st", {} }, + .{ "saotome.st", {} }, + .{ "store.st", {} }, + .{ "su", {} }, + .{ "sv", {} }, + .{ "com.sv", {} }, + .{ "edu.sv", {} }, + .{ "gob.sv", {} }, + .{ "org.sv", {} }, + .{ "red.sv", {} }, + .{ "sx", {} }, + .{ "gov.sx", {} }, + .{ "sy", {} }, + .{ "com.sy", {} }, + .{ "edu.sy", {} }, + .{ "gov.sy", {} }, + .{ "mil.sy", {} }, + .{ "net.sy", {} }, + .{ "org.sy", {} }, + .{ "sz", {} }, + .{ "ac.sz", {} }, + .{ "co.sz", {} }, + .{ "org.sz", {} }, + .{ "tc", {} }, + .{ "td", {} }, + .{ "tel", {} }, + .{ "tf", {} }, + .{ "tg", {} }, + .{ "th", {} }, + .{ "ac.th", {} }, + .{ "co.th", {} }, + .{ "go.th", {} }, + .{ "in.th", {} }, + .{ "mi.th", {} }, + .{ "net.th", {} }, + .{ "or.th", {} }, + .{ "tj", {} }, + .{ "ac.tj", {} }, + .{ "biz.tj", {} }, + .{ "co.tj", {} }, + .{ "com.tj", {} }, + .{ "edu.tj", {} }, + .{ "go.tj", {} }, + .{ "gov.tj", {} }, + .{ "int.tj", {} }, + .{ "mil.tj", {} }, + .{ "name.tj", {} }, + .{ "net.tj", {} }, + .{ "nic.tj", {} }, + .{ "org.tj", {} }, + .{ "test.tj", {} }, + .{ "web.tj", {} }, + .{ "tk", {} }, + .{ "tl", {} }, + .{ "gov.tl", {} }, + .{ "tm", {} }, + .{ "co.tm", {} }, + .{ "com.tm", {} }, + .{ "edu.tm", {} }, + .{ "gov.tm", {} }, + .{ "mil.tm", {} }, + .{ "net.tm", {} }, + .{ "nom.tm", {} }, + .{ "org.tm", {} }, + .{ "tn", {} }, + .{ "com.tn", {} }, + .{ "ens.tn", {} }, + .{ "fin.tn", {} }, + .{ "gov.tn", {} }, + .{ "ind.tn", {} }, + .{ "info.tn", {} }, + .{ "intl.tn", {} }, + .{ "mincom.tn", {} }, + .{ "nat.tn", {} }, + .{ "net.tn", {} }, + .{ "org.tn", {} }, + .{ "perso.tn", {} }, + .{ "tourism.tn", {} }, + .{ "to", {} }, + .{ "com.to", {} }, + .{ "edu.to", {} }, + .{ "gov.to", {} }, + .{ "mil.to", {} }, + .{ "net.to", {} }, + .{ "org.to", {} }, + .{ "tr", {} }, + .{ "av.tr", {} }, + .{ "bbs.tr", {} }, + .{ "bel.tr", {} }, + .{ "biz.tr", {} }, + .{ "com.tr", {} }, + .{ "dr.tr", {} }, + .{ "edu.tr", {} }, + .{ "gen.tr", {} }, + .{ "gov.tr", {} }, + .{ "info.tr", {} }, + .{ "k12.tr", {} }, + .{ "kep.tr", {} }, + .{ "mil.tr", {} }, + .{ "name.tr", {} }, + .{ "net.tr", {} }, + .{ "org.tr", {} }, + .{ "pol.tr", {} }, + .{ "tel.tr", {} }, + .{ "tsk.tr", {} }, + .{ "tv.tr", {} }, + .{ "web.tr", {} }, + .{ "nc.tr", {} }, + .{ "gov.nc.tr", {} }, + .{ "tt", {} }, + .{ "biz.tt", {} }, + .{ "co.tt", {} }, + .{ "com.tt", {} }, + .{ "edu.tt", {} }, + .{ "gov.tt", {} }, + .{ "info.tt", {} }, + .{ "mil.tt", {} }, + .{ "name.tt", {} }, + .{ "net.tt", {} }, + .{ "org.tt", {} }, + .{ "pro.tt", {} }, + .{ "tv", {} }, + .{ "tw", {} }, + .{ "club.tw", {} }, + .{ "com.tw", {} }, + .{ "ebiz.tw", {} }, + .{ "edu.tw", {} }, + .{ "game.tw", {} }, + .{ "gov.tw", {} }, + .{ "idv.tw", {} }, + .{ "mil.tw", {} }, + .{ "net.tw", {} }, + .{ "org.tw", {} }, + .{ "tz", {} }, + .{ "ac.tz", {} }, + .{ "co.tz", {} }, + .{ "go.tz", {} }, + .{ "hotel.tz", {} }, + .{ "info.tz", {} }, + .{ "me.tz", {} }, + .{ "mil.tz", {} }, + .{ "mobi.tz", {} }, + .{ "ne.tz", {} }, + .{ "or.tz", {} }, + .{ "sc.tz", {} }, + .{ "tv.tz", {} }, + .{ "ua", {} }, + .{ "com.ua", {} }, + .{ "edu.ua", {} }, + .{ "gov.ua", {} }, + .{ "in.ua", {} }, + .{ "net.ua", {} }, + .{ "org.ua", {} }, + .{ "cherkassy.ua", {} }, + .{ "cherkasy.ua", {} }, + .{ "chernigov.ua", {} }, + .{ "chernihiv.ua", {} }, + .{ "chernivtsi.ua", {} }, + .{ "chernovtsy.ua", {} }, + .{ "ck.ua", {} }, + .{ "cn.ua", {} }, + .{ "cr.ua", {} }, + .{ "crimea.ua", {} }, + .{ "cv.ua", {} }, + .{ "dn.ua", {} }, + .{ "dnepropetrovsk.ua", {} }, + .{ "dnipropetrovsk.ua", {} }, + .{ "donetsk.ua", {} }, + .{ "dp.ua", {} }, + .{ "if.ua", {} }, + .{ "ivano-frankivsk.ua", {} }, + .{ "kh.ua", {} }, + .{ "kharkiv.ua", {} }, + .{ "kharkov.ua", {} }, + .{ "kherson.ua", {} }, + .{ "khmelnitskiy.ua", {} }, + .{ "khmelnytskyi.ua", {} }, + .{ "kiev.ua", {} }, + .{ "kirovograd.ua", {} }, + .{ "km.ua", {} }, + .{ "kr.ua", {} }, + .{ "kropyvnytskyi.ua", {} }, + .{ "krym.ua", {} }, + .{ "ks.ua", {} }, + .{ "kv.ua", {} }, + .{ "kyiv.ua", {} }, + .{ "lg.ua", {} }, + .{ "lt.ua", {} }, + .{ "lugansk.ua", {} }, + .{ "luhansk.ua", {} }, + .{ "lutsk.ua", {} }, + .{ "lv.ua", {} }, + .{ "lviv.ua", {} }, + .{ "mk.ua", {} }, + .{ "mykolaiv.ua", {} }, + .{ "nikolaev.ua", {} }, + .{ "od.ua", {} }, + .{ "odesa.ua", {} }, + .{ "odessa.ua", {} }, + .{ "pl.ua", {} }, + .{ "poltava.ua", {} }, + .{ "rivne.ua", {} }, + .{ "rovno.ua", {} }, + .{ "rv.ua", {} }, + .{ "sb.ua", {} }, + .{ "sebastopol.ua", {} }, + .{ "sevastopol.ua", {} }, + .{ "sm.ua", {} }, + .{ "sumy.ua", {} }, + .{ "te.ua", {} }, + .{ "ternopil.ua", {} }, + .{ "uz.ua", {} }, + .{ "uzhgorod.ua", {} }, + .{ "uzhhorod.ua", {} }, + .{ "vinnica.ua", {} }, + .{ "vinnytsia.ua", {} }, + .{ "vn.ua", {} }, + .{ "volyn.ua", {} }, + .{ "yalta.ua", {} }, + .{ "zakarpattia.ua", {} }, + .{ "zaporizhzhe.ua", {} }, + .{ "zaporizhzhia.ua", {} }, + .{ "zhitomir.ua", {} }, + .{ "zhytomyr.ua", {} }, + .{ "zp.ua", {} }, + .{ "zt.ua", {} }, + .{ "ug", {} }, + .{ "ac.ug", {} }, + .{ "co.ug", {} }, + .{ "com.ug", {} }, + .{ "edu.ug", {} }, + .{ "go.ug", {} }, + .{ "gov.ug", {} }, + .{ "mil.ug", {} }, + .{ "ne.ug", {} }, + .{ "or.ug", {} }, + .{ "org.ug", {} }, + .{ "sc.ug", {} }, + .{ "us.ug", {} }, + .{ "uk", {} }, + .{ "ac.uk", {} }, + .{ "co.uk", {} }, + .{ "gov.uk", {} }, + .{ "ltd.uk", {} }, + .{ "me.uk", {} }, + .{ "net.uk", {} }, + .{ "nhs.uk", {} }, + .{ "org.uk", {} }, + .{ "plc.uk", {} }, + .{ "police.uk", {} }, + .{ "*.sch.uk", {} }, + .{ "us", {} }, + .{ "dni.us", {} }, + .{ "isa.us", {} }, + .{ "nsn.us", {} }, + .{ "ak.us", {} }, + .{ "al.us", {} }, + .{ "ar.us", {} }, + .{ "as.us", {} }, + .{ "az.us", {} }, + .{ "ca.us", {} }, + .{ "co.us", {} }, + .{ "ct.us", {} }, + .{ "dc.us", {} }, + .{ "de.us", {} }, + .{ "fl.us", {} }, + .{ "ga.us", {} }, + .{ "gu.us", {} }, + .{ "hi.us", {} }, + .{ "ia.us", {} }, + .{ "id.us", {} }, + .{ "il.us", {} }, + .{ "in.us", {} }, + .{ "ks.us", {} }, + .{ "ky.us", {} }, + .{ "la.us", {} }, + .{ "ma.us", {} }, + .{ "md.us", {} }, + .{ "me.us", {} }, + .{ "mi.us", {} }, + .{ "mn.us", {} }, + .{ "mo.us", {} }, + .{ "ms.us", {} }, + .{ "mt.us", {} }, + .{ "nc.us", {} }, + .{ "nd.us", {} }, + .{ "ne.us", {} }, + .{ "nh.us", {} }, + .{ "nj.us", {} }, + .{ "nm.us", {} }, + .{ "nv.us", {} }, + .{ "ny.us", {} }, + .{ "oh.us", {} }, + .{ "ok.us", {} }, + .{ "or.us", {} }, + .{ "pa.us", {} }, + .{ "pr.us", {} }, + .{ "ri.us", {} }, + .{ "sc.us", {} }, + .{ "sd.us", {} }, + .{ "tn.us", {} }, + .{ "tx.us", {} }, + .{ "ut.us", {} }, + .{ "va.us", {} }, + .{ "vi.us", {} }, + .{ "vt.us", {} }, + .{ "wa.us", {} }, + .{ "wi.us", {} }, + .{ "wv.us", {} }, + .{ "wy.us", {} }, + .{ "k12.ak.us", {} }, + .{ "k12.al.us", {} }, + .{ "k12.ar.us", {} }, + .{ "k12.as.us", {} }, + .{ "k12.az.us", {} }, + .{ "k12.ca.us", {} }, + .{ "k12.co.us", {} }, + .{ "k12.ct.us", {} }, + .{ "k12.dc.us", {} }, + .{ "k12.fl.us", {} }, + .{ "k12.ga.us", {} }, + .{ "k12.gu.us", {} }, + .{ "k12.ia.us", {} }, + .{ "k12.id.us", {} }, + .{ "k12.il.us", {} }, + .{ "k12.in.us", {} }, + .{ "k12.ks.us", {} }, + .{ "k12.ky.us", {} }, + .{ "k12.la.us", {} }, + .{ "k12.ma.us", {} }, + .{ "k12.md.us", {} }, + .{ "k12.me.us", {} }, + .{ "k12.mi.us", {} }, + .{ "k12.mn.us", {} }, + .{ "k12.mo.us", {} }, + .{ "k12.ms.us", {} }, + .{ "k12.mt.us", {} }, + .{ "k12.nc.us", {} }, + .{ "k12.ne.us", {} }, + .{ "k12.nh.us", {} }, + .{ "k12.nj.us", {} }, + .{ "k12.nm.us", {} }, + .{ "k12.nv.us", {} }, + .{ "k12.ny.us", {} }, + .{ "k12.oh.us", {} }, + .{ "k12.ok.us", {} }, + .{ "k12.or.us", {} }, + .{ "k12.pa.us", {} }, + .{ "k12.pr.us", {} }, + .{ "k12.sc.us", {} }, + .{ "k12.tn.us", {} }, + .{ "k12.tx.us", {} }, + .{ "k12.ut.us", {} }, + .{ "k12.va.us", {} }, + .{ "k12.vi.us", {} }, + .{ "k12.vt.us", {} }, + .{ "k12.wa.us", {} }, + .{ "k12.wi.us", {} }, + .{ "cc.ak.us", {} }, + .{ "lib.ak.us", {} }, + .{ "cc.al.us", {} }, + .{ "lib.al.us", {} }, + .{ "cc.ar.us", {} }, + .{ "lib.ar.us", {} }, + .{ "cc.as.us", {} }, + .{ "lib.as.us", {} }, + .{ "cc.az.us", {} }, + .{ "lib.az.us", {} }, + .{ "cc.ca.us", {} }, + .{ "lib.ca.us", {} }, + .{ "cc.co.us", {} }, + .{ "lib.co.us", {} }, + .{ "cc.ct.us", {} }, + .{ "lib.ct.us", {} }, + .{ "cc.dc.us", {} }, + .{ "lib.dc.us", {} }, + .{ "cc.de.us", {} }, + .{ "cc.fl.us", {} }, + .{ "cc.ga.us", {} }, + .{ "cc.gu.us", {} }, + .{ "cc.hi.us", {} }, + .{ "cc.ia.us", {} }, + .{ "cc.id.us", {} }, + .{ "cc.il.us", {} }, + .{ "cc.in.us", {} }, + .{ "cc.ks.us", {} }, + .{ "cc.ky.us", {} }, + .{ "cc.la.us", {} }, + .{ "cc.ma.us", {} }, + .{ "cc.md.us", {} }, + .{ "cc.me.us", {} }, + .{ "cc.mi.us", {} }, + .{ "cc.mn.us", {} }, + .{ "cc.mo.us", {} }, + .{ "cc.ms.us", {} }, + .{ "cc.mt.us", {} }, + .{ "cc.nc.us", {} }, + .{ "cc.nd.us", {} }, + .{ "cc.ne.us", {} }, + .{ "cc.nh.us", {} }, + .{ "cc.nj.us", {} }, + .{ "cc.nm.us", {} }, + .{ "cc.nv.us", {} }, + .{ "cc.ny.us", {} }, + .{ "cc.oh.us", {} }, + .{ "cc.ok.us", {} }, + .{ "cc.or.us", {} }, + .{ "cc.pa.us", {} }, + .{ "cc.pr.us", {} }, + .{ "cc.ri.us", {} }, + .{ "cc.sc.us", {} }, + .{ "cc.sd.us", {} }, + .{ "cc.tn.us", {} }, + .{ "cc.tx.us", {} }, + .{ "cc.ut.us", {} }, + .{ "cc.va.us", {} }, + .{ "cc.vi.us", {} }, + .{ "cc.vt.us", {} }, + .{ "cc.wa.us", {} }, + .{ "cc.wi.us", {} }, + .{ "cc.wv.us", {} }, + .{ "cc.wy.us", {} }, + .{ "k12.wy.us", {} }, + .{ "lib.fl.us", {} }, + .{ "lib.ga.us", {} }, + .{ "lib.gu.us", {} }, + .{ "lib.hi.us", {} }, + .{ "lib.ia.us", {} }, + .{ "lib.id.us", {} }, + .{ "lib.il.us", {} }, + .{ "lib.in.us", {} }, + .{ "lib.ks.us", {} }, + .{ "lib.ky.us", {} }, + .{ "lib.la.us", {} }, + .{ "lib.ma.us", {} }, + .{ "lib.md.us", {} }, + .{ "lib.me.us", {} }, + .{ "lib.mi.us", {} }, + .{ "lib.mn.us", {} }, + .{ "lib.mo.us", {} }, + .{ "lib.ms.us", {} }, + .{ "lib.mt.us", {} }, + .{ "lib.nc.us", {} }, + .{ "lib.nd.us", {} }, + .{ "lib.ne.us", {} }, + .{ "lib.nh.us", {} }, + .{ "lib.nj.us", {} }, + .{ "lib.nm.us", {} }, + .{ "lib.nv.us", {} }, + .{ "lib.ny.us", {} }, + .{ "lib.oh.us", {} }, + .{ "lib.ok.us", {} }, + .{ "lib.or.us", {} }, + .{ "lib.pa.us", {} }, + .{ "lib.pr.us", {} }, + .{ "lib.ri.us", {} }, + .{ "lib.sc.us", {} }, + .{ "lib.sd.us", {} }, + .{ "lib.tn.us", {} }, + .{ "lib.tx.us", {} }, + .{ "lib.ut.us", {} }, + .{ "lib.va.us", {} }, + .{ "lib.vi.us", {} }, + .{ "lib.vt.us", {} }, + .{ "lib.wa.us", {} }, + .{ "lib.wi.us", {} }, + .{ "lib.wy.us", {} }, + .{ "chtr.k12.ma.us", {} }, + .{ "paroch.k12.ma.us", {} }, + .{ "pvt.k12.ma.us", {} }, + .{ "ann-arbor.mi.us", {} }, + .{ "cog.mi.us", {} }, + .{ "dst.mi.us", {} }, + .{ "eaton.mi.us", {} }, + .{ "gen.mi.us", {} }, + .{ "mus.mi.us", {} }, + .{ "tec.mi.us", {} }, + .{ "washtenaw.mi.us", {} }, + .{ "uy", {} }, + .{ "com.uy", {} }, + .{ "edu.uy", {} }, + .{ "gub.uy", {} }, + .{ "mil.uy", {} }, + .{ "net.uy", {} }, + .{ "org.uy", {} }, + .{ "uz", {} }, + .{ "co.uz", {} }, + .{ "com.uz", {} }, + .{ "net.uz", {} }, + .{ "org.uz", {} }, + .{ "va", {} }, + .{ "vc", {} }, + .{ "com.vc", {} }, + .{ "edu.vc", {} }, + .{ "gov.vc", {} }, + .{ "mil.vc", {} }, + .{ "net.vc", {} }, + .{ "org.vc", {} }, + .{ "ve", {} }, + .{ "arts.ve", {} }, + .{ "bib.ve", {} }, + .{ "co.ve", {} }, + .{ "com.ve", {} }, + .{ "e12.ve", {} }, + .{ "edu.ve", {} }, + .{ "emprende.ve", {} }, + .{ "firm.ve", {} }, + .{ "gob.ve", {} }, + .{ "gov.ve", {} }, + .{ "info.ve", {} }, + .{ "int.ve", {} }, + .{ "mil.ve", {} }, + .{ "net.ve", {} }, + .{ "nom.ve", {} }, + .{ "org.ve", {} }, + .{ "rar.ve", {} }, + .{ "rec.ve", {} }, + .{ "store.ve", {} }, + .{ "tec.ve", {} }, + .{ "web.ve", {} }, + .{ "vg", {} }, + .{ "edu.vg", {} }, + .{ "vi", {} }, + .{ "co.vi", {} }, + .{ "com.vi", {} }, + .{ "k12.vi", {} }, + .{ "net.vi", {} }, + .{ "org.vi", {} }, + .{ "vn", {} }, + .{ "ac.vn", {} }, + .{ "ai.vn", {} }, + .{ "biz.vn", {} }, + .{ "com.vn", {} }, + .{ "edu.vn", {} }, + .{ "gov.vn", {} }, + .{ "health.vn", {} }, + .{ "id.vn", {} }, + .{ "info.vn", {} }, + .{ "int.vn", {} }, + .{ "io.vn", {} }, + .{ "name.vn", {} }, + .{ "net.vn", {} }, + .{ "org.vn", {} }, + .{ "pro.vn", {} }, + .{ "angiang.vn", {} }, + .{ "bacgiang.vn", {} }, + .{ "backan.vn", {} }, + .{ "baclieu.vn", {} }, + .{ "bacninh.vn", {} }, + .{ "baria-vungtau.vn", {} }, + .{ "bentre.vn", {} }, + .{ "binhdinh.vn", {} }, + .{ "binhduong.vn", {} }, + .{ "binhphuoc.vn", {} }, + .{ "binhthuan.vn", {} }, + .{ "camau.vn", {} }, + .{ "cantho.vn", {} }, + .{ "caobang.vn", {} }, + .{ "daklak.vn", {} }, + .{ "daknong.vn", {} }, + .{ "danang.vn", {} }, + .{ "dienbien.vn", {} }, + .{ "dongnai.vn", {} }, + .{ "dongthap.vn", {} }, + .{ "gialai.vn", {} }, + .{ "hagiang.vn", {} }, + .{ "haiduong.vn", {} }, + .{ "haiphong.vn", {} }, + .{ "hanam.vn", {} }, + .{ "hanoi.vn", {} }, + .{ "hatinh.vn", {} }, + .{ "haugiang.vn", {} }, + .{ "hoabinh.vn", {} }, + .{ "hungyen.vn", {} }, + .{ "khanhhoa.vn", {} }, + .{ "kiengiang.vn", {} }, + .{ "kontum.vn", {} }, + .{ "laichau.vn", {} }, + .{ "lamdong.vn", {} }, + .{ "langson.vn", {} }, + .{ "laocai.vn", {} }, + .{ "longan.vn", {} }, + .{ "namdinh.vn", {} }, + .{ "nghean.vn", {} }, + .{ "ninhbinh.vn", {} }, + .{ "ninhthuan.vn", {} }, + .{ "phutho.vn", {} }, + .{ "phuyen.vn", {} }, + .{ "quangbinh.vn", {} }, + .{ "quangnam.vn", {} }, + .{ "quangngai.vn", {} }, + .{ "quangninh.vn", {} }, + .{ "quangtri.vn", {} }, + .{ "soctrang.vn", {} }, + .{ "sonla.vn", {} }, + .{ "tayninh.vn", {} }, + .{ "thaibinh.vn", {} }, + .{ "thainguyen.vn", {} }, + .{ "thanhhoa.vn", {} }, + .{ "thanhphohochiminh.vn", {} }, + .{ "thuathienhue.vn", {} }, + .{ "tiengiang.vn", {} }, + .{ "travinh.vn", {} }, + .{ "tuyenquang.vn", {} }, + .{ "vinhlong.vn", {} }, + .{ "vinhphuc.vn", {} }, + .{ "yenbai.vn", {} }, + .{ "vu", {} }, + .{ "com.vu", {} }, + .{ "edu.vu", {} }, + .{ "net.vu", {} }, + .{ "org.vu", {} }, + .{ "wf", {} }, + .{ "ws", {} }, + .{ "com.ws", {} }, + .{ "edu.ws", {} }, + .{ "gov.ws", {} }, + .{ "net.ws", {} }, + .{ "org.ws", {} }, + .{ "yt", {} }, + .{ "امارات", {} }, + .{ "հայ", {} }, + .{ "বাংলা", {} }, + .{ "бг", {} }, + .{ "البحرين", {} }, + .{ "бел", {} }, + .{ "中国", {} }, + .{ "中國", {} }, + .{ "الجزائر", {} }, + .{ "مصر", {} }, + .{ "ею", {} }, + .{ "ευ", {} }, + .{ "موريتانيا", {} }, + .{ "გე", {} }, + .{ "ελ", {} }, + .{ "香港", {} }, + .{ "個人.香港", {} }, + .{ "公司.香港", {} }, + .{ "政府.香港", {} }, + .{ "教育.香港", {} }, + .{ "組織.香港", {} }, + .{ "網絡.香港", {} }, + .{ "ಭಾರತ", {} }, + .{ "ଭାରତ", {} }, + .{ "ভাৰত", {} }, + .{ "भारतम्", {} }, + .{ "भारोत", {} }, + .{ "ڀارت", {} }, + .{ "ഭാരതം", {} }, + .{ "भारत", {} }, + .{ "بارت", {} }, + .{ "بھارت", {} }, + .{ "భారత్", {} }, + .{ "ભારત", {} }, + .{ "ਭਾਰਤ", {} }, + .{ "ভারত", {} }, + .{ "இந்தியா", {} }, + .{ "ایران", {} }, + .{ "ايران", {} }, + .{ "عراق", {} }, + .{ "الاردن", {} }, + .{ "한국", {} }, + .{ "қаз", {} }, + .{ "ລາວ", {} }, + .{ "ලංකා", {} }, + .{ "இலங்கை", {} }, + .{ "المغرب", {} }, + .{ "мкд", {} }, + .{ "мон", {} }, + .{ "澳門", {} }, + .{ "澳门", {} }, + .{ "مليسيا", {} }, + .{ "عمان", {} }, + .{ "پاکستان", {} }, + .{ "پاكستان", {} }, + .{ "فلسطين", {} }, + .{ "срб", {} }, + .{ "ак.срб", {} }, + .{ "обр.срб", {} }, + .{ "од.срб", {} }, + .{ "орг.срб", {} }, + .{ "пр.срб", {} }, + .{ "упр.срб", {} }, + .{ "рф", {} }, + .{ "قطر", {} }, + .{ "السعودية", {} }, + .{ "السعودیة", {} }, + .{ "السعودیۃ", {} }, + .{ "السعوديه", {} }, + .{ "سودان", {} }, + .{ "新加坡", {} }, + .{ "சிங்கப்பூர்", {} }, + .{ "سورية", {} }, + .{ "سوريا", {} }, + .{ "ไทย", {} }, + .{ "ทหาร.ไทย", {} }, + .{ "ธุรกิจ.ไทย", {} }, + .{ "เน็ต.ไทย", {} }, + .{ "รัฐบาล.ไทย", {} }, + .{ "ศึกษา.ไทย", {} }, + .{ "องค์กร.ไทย", {} }, + .{ "تونس", {} }, + .{ "台灣", {} }, + .{ "台湾", {} }, + .{ "臺灣", {} }, + .{ "укр", {} }, + .{ "اليمن", {} }, + .{ "xxx", {} }, + .{ "ye", {} }, + .{ "com.ye", {} }, + .{ "edu.ye", {} }, + .{ "gov.ye", {} }, + .{ "mil.ye", {} }, + .{ "net.ye", {} }, + .{ "org.ye", {} }, + .{ "ac.za", {} }, + .{ "agric.za", {} }, + .{ "alt.za", {} }, + .{ "co.za", {} }, + .{ "edu.za", {} }, + .{ "gov.za", {} }, + .{ "grondar.za", {} }, + .{ "law.za", {} }, + .{ "mil.za", {} }, + .{ "net.za", {} }, + .{ "ngo.za", {} }, + .{ "nic.za", {} }, + .{ "nis.za", {} }, + .{ "nom.za", {} }, + .{ "org.za", {} }, + .{ "school.za", {} }, + .{ "tm.za", {} }, + .{ "web.za", {} }, + .{ "zm", {} }, + .{ "ac.zm", {} }, + .{ "biz.zm", {} }, + .{ "co.zm", {} }, + .{ "com.zm", {} }, + .{ "edu.zm", {} }, + .{ "gov.zm", {} }, + .{ "info.zm", {} }, + .{ "mil.zm", {} }, + .{ "net.zm", {} }, + .{ "org.zm", {} }, + .{ "sch.zm", {} }, + .{ "zw", {} }, + .{ "ac.zw", {} }, + .{ "co.zw", {} }, + .{ "gov.zw", {} }, + .{ "mil.zw", {} }, + .{ "org.zw", {} }, + .{ "aaa", {} }, + .{ "aarp", {} }, + .{ "abb", {} }, + .{ "abbott", {} }, + .{ "abbvie", {} }, + .{ "abc", {} }, + .{ "able", {} }, + .{ "abogado", {} }, + .{ "abudhabi", {} }, + .{ "academy", {} }, + .{ "accenture", {} }, + .{ "accountant", {} }, + .{ "accountants", {} }, + .{ "aco", {} }, + .{ "actor", {} }, + .{ "ads", {} }, + .{ "adult", {} }, + .{ "aeg", {} }, + .{ "aetna", {} }, + .{ "afl", {} }, + .{ "africa", {} }, + .{ "agakhan", {} }, + .{ "agency", {} }, + .{ "aig", {} }, + .{ "airbus", {} }, + .{ "airforce", {} }, + .{ "airtel", {} }, + .{ "akdn", {} }, + .{ "alibaba", {} }, + .{ "alipay", {} }, + .{ "allfinanz", {} }, + .{ "allstate", {} }, + .{ "ally", {} }, + .{ "alsace", {} }, + .{ "alstom", {} }, + .{ "amazon", {} }, + .{ "americanexpress", {} }, + .{ "americanfamily", {} }, + .{ "amex", {} }, + .{ "amfam", {} }, + .{ "amica", {} }, + .{ "amsterdam", {} }, + .{ "analytics", {} }, + .{ "android", {} }, + .{ "anquan", {} }, + .{ "anz", {} }, + .{ "aol", {} }, + .{ "apartments", {} }, + .{ "app", {} }, + .{ "apple", {} }, + .{ "aquarelle", {} }, + .{ "arab", {} }, + .{ "aramco", {} }, + .{ "archi", {} }, + .{ "army", {} }, + .{ "art", {} }, + .{ "arte", {} }, + .{ "asda", {} }, + .{ "associates", {} }, + .{ "athleta", {} }, + .{ "attorney", {} }, + .{ "auction", {} }, + .{ "audi", {} }, + .{ "audible", {} }, + .{ "audio", {} }, + .{ "auspost", {} }, + .{ "author", {} }, + .{ "auto", {} }, + .{ "autos", {} }, + .{ "aws", {} }, + .{ "axa", {} }, + .{ "azure", {} }, + .{ "baby", {} }, + .{ "baidu", {} }, + .{ "banamex", {} }, + .{ "band", {} }, + .{ "bank", {} }, + .{ "bar", {} }, + .{ "barcelona", {} }, + .{ "barclaycard", {} }, + .{ "barclays", {} }, + .{ "barefoot", {} }, + .{ "bargains", {} }, + .{ "baseball", {} }, + .{ "basketball", {} }, + .{ "bauhaus", {} }, + .{ "bayern", {} }, + .{ "bbc", {} }, + .{ "bbt", {} }, + .{ "bbva", {} }, + .{ "bcg", {} }, + .{ "bcn", {} }, + .{ "beats", {} }, + .{ "beauty", {} }, + .{ "beer", {} }, + .{ "bentley", {} }, + .{ "berlin", {} }, + .{ "best", {} }, + .{ "bestbuy", {} }, + .{ "bet", {} }, + .{ "bharti", {} }, + .{ "bible", {} }, + .{ "bid", {} }, + .{ "bike", {} }, + .{ "bing", {} }, + .{ "bingo", {} }, + .{ "bio", {} }, + .{ "black", {} }, + .{ "blackfriday", {} }, + .{ "blockbuster", {} }, + .{ "blog", {} }, + .{ "bloomberg", {} }, + .{ "blue", {} }, + .{ "bms", {} }, + .{ "bmw", {} }, + .{ "bnpparibas", {} }, + .{ "boats", {} }, + .{ "boehringer", {} }, + .{ "bofa", {} }, + .{ "bom", {} }, + .{ "bond", {} }, + .{ "boo", {} }, + .{ "book", {} }, + .{ "booking", {} }, + .{ "bosch", {} }, + .{ "bostik", {} }, + .{ "boston", {} }, + .{ "bot", {} }, + .{ "boutique", {} }, + .{ "box", {} }, + .{ "bradesco", {} }, + .{ "bridgestone", {} }, + .{ "broadway", {} }, + .{ "broker", {} }, + .{ "brother", {} }, + .{ "brussels", {} }, + .{ "build", {} }, + .{ "builders", {} }, + .{ "business", {} }, + .{ "buy", {} }, + .{ "buzz", {} }, + .{ "bzh", {} }, + .{ "cab", {} }, + .{ "cafe", {} }, + .{ "cal", {} }, + .{ "call", {} }, + .{ "calvinklein", {} }, + .{ "cam", {} }, + .{ "camera", {} }, + .{ "camp", {} }, + .{ "canon", {} }, + .{ "capetown", {} }, + .{ "capital", {} }, + .{ "capitalone", {} }, + .{ "car", {} }, + .{ "caravan", {} }, + .{ "cards", {} }, + .{ "care", {} }, + .{ "career", {} }, + .{ "careers", {} }, + .{ "cars", {} }, + .{ "casa", {} }, + .{ "case", {} }, + .{ "cash", {} }, + .{ "casino", {} }, + .{ "catering", {} }, + .{ "catholic", {} }, + .{ "cba", {} }, + .{ "cbn", {} }, + .{ "cbre", {} }, + .{ "center", {} }, + .{ "ceo", {} }, + .{ "cern", {} }, + .{ "cfa", {} }, + .{ "cfd", {} }, + .{ "chanel", {} }, + .{ "channel", {} }, + .{ "charity", {} }, + .{ "chase", {} }, + .{ "chat", {} }, + .{ "cheap", {} }, + .{ "chintai", {} }, + .{ "christmas", {} }, + .{ "chrome", {} }, + .{ "church", {} }, + .{ "cipriani", {} }, + .{ "circle", {} }, + .{ "cisco", {} }, + .{ "citadel", {} }, + .{ "citi", {} }, + .{ "citic", {} }, + .{ "city", {} }, + .{ "claims", {} }, + .{ "cleaning", {} }, + .{ "click", {} }, + .{ "clinic", {} }, + .{ "clinique", {} }, + .{ "clothing", {} }, + .{ "cloud", {} }, + .{ "club", {} }, + .{ "clubmed", {} }, + .{ "coach", {} }, + .{ "codes", {} }, + .{ "coffee", {} }, + .{ "college", {} }, + .{ "cologne", {} }, + .{ "commbank", {} }, + .{ "community", {} }, + .{ "company", {} }, + .{ "compare", {} }, + .{ "computer", {} }, + .{ "comsec", {} }, + .{ "condos", {} }, + .{ "construction", {} }, + .{ "consulting", {} }, + .{ "contact", {} }, + .{ "contractors", {} }, + .{ "cooking", {} }, + .{ "cool", {} }, + .{ "corsica", {} }, + .{ "country", {} }, + .{ "coupon", {} }, + .{ "coupons", {} }, + .{ "courses", {} }, + .{ "cpa", {} }, + .{ "credit", {} }, + .{ "creditcard", {} }, + .{ "creditunion", {} }, + .{ "cricket", {} }, + .{ "crown", {} }, + .{ "crs", {} }, + .{ "cruise", {} }, + .{ "cruises", {} }, + .{ "cuisinella", {} }, + .{ "cymru", {} }, + .{ "cyou", {} }, + .{ "dad", {} }, + .{ "dance", {} }, + .{ "data", {} }, + .{ "date", {} }, + .{ "dating", {} }, + .{ "datsun", {} }, + .{ "day", {} }, + .{ "dclk", {} }, + .{ "dds", {} }, + .{ "deal", {} }, + .{ "dealer", {} }, + .{ "deals", {} }, + .{ "degree", {} }, + .{ "delivery", {} }, + .{ "dell", {} }, + .{ "deloitte", {} }, + .{ "delta", {} }, + .{ "democrat", {} }, + .{ "dental", {} }, + .{ "dentist", {} }, + .{ "desi", {} }, + .{ "design", {} }, + .{ "dev", {} }, + .{ "dhl", {} }, + .{ "diamonds", {} }, + .{ "diet", {} }, + .{ "digital", {} }, + .{ "direct", {} }, + .{ "directory", {} }, + .{ "discount", {} }, + .{ "discover", {} }, + .{ "dish", {} }, + .{ "diy", {} }, + .{ "dnp", {} }, + .{ "docs", {} }, + .{ "doctor", {} }, + .{ "dog", {} }, + .{ "domains", {} }, + .{ "dot", {} }, + .{ "download", {} }, + .{ "drive", {} }, + .{ "dtv", {} }, + .{ "dubai", {} }, + .{ "dunlop", {} }, + .{ "dupont", {} }, + .{ "durban", {} }, + .{ "dvag", {} }, + .{ "dvr", {} }, + .{ "earth", {} }, + .{ "eat", {} }, + .{ "eco", {} }, + .{ "edeka", {} }, + .{ "education", {} }, + .{ "email", {} }, + .{ "emerck", {} }, + .{ "energy", {} }, + .{ "engineer", {} }, + .{ "engineering", {} }, + .{ "enterprises", {} }, + .{ "epson", {} }, + .{ "equipment", {} }, + .{ "ericsson", {} }, + .{ "erni", {} }, + .{ "esq", {} }, + .{ "estate", {} }, + .{ "eurovision", {} }, + .{ "eus", {} }, + .{ "events", {} }, + .{ "exchange", {} }, + .{ "expert", {} }, + .{ "exposed", {} }, + .{ "express", {} }, + .{ "extraspace", {} }, + .{ "fage", {} }, + .{ "fail", {} }, + .{ "fairwinds", {} }, + .{ "faith", {} }, + .{ "family", {} }, + .{ "fan", {} }, + .{ "fans", {} }, + .{ "farm", {} }, + .{ "farmers", {} }, + .{ "fashion", {} }, + .{ "fast", {} }, + .{ "fedex", {} }, + .{ "feedback", {} }, + .{ "ferrari", {} }, + .{ "ferrero", {} }, + .{ "fidelity", {} }, + .{ "fido", {} }, + .{ "film", {} }, + .{ "final", {} }, + .{ "finance", {} }, + .{ "financial", {} }, + .{ "fire", {} }, + .{ "firestone", {} }, + .{ "firmdale", {} }, + .{ "fish", {} }, + .{ "fishing", {} }, + .{ "fit", {} }, + .{ "fitness", {} }, + .{ "flickr", {} }, + .{ "flights", {} }, + .{ "flir", {} }, + .{ "florist", {} }, + .{ "flowers", {} }, + .{ "fly", {} }, + .{ "foo", {} }, + .{ "food", {} }, + .{ "football", {} }, + .{ "ford", {} }, + .{ "forex", {} }, + .{ "forsale", {} }, + .{ "forum", {} }, + .{ "foundation", {} }, + .{ "fox", {} }, + .{ "free", {} }, + .{ "fresenius", {} }, + .{ "frl", {} }, + .{ "frogans", {} }, + .{ "frontier", {} }, + .{ "ftr", {} }, + .{ "fujitsu", {} }, + .{ "fun", {} }, + .{ "fund", {} }, + .{ "furniture", {} }, + .{ "futbol", {} }, + .{ "fyi", {} }, + .{ "gal", {} }, + .{ "gallery", {} }, + .{ "gallo", {} }, + .{ "gallup", {} }, + .{ "game", {} }, + .{ "games", {} }, + .{ "gap", {} }, + .{ "garden", {} }, + .{ "gay", {} }, + .{ "gbiz", {} }, + .{ "gdn", {} }, + .{ "gea", {} }, + .{ "gent", {} }, + .{ "genting", {} }, + .{ "george", {} }, + .{ "ggee", {} }, + .{ "gift", {} }, + .{ "gifts", {} }, + .{ "gives", {} }, + .{ "giving", {} }, + .{ "glass", {} }, + .{ "gle", {} }, + .{ "global", {} }, + .{ "globo", {} }, + .{ "gmail", {} }, + .{ "gmbh", {} }, + .{ "gmo", {} }, + .{ "gmx", {} }, + .{ "godaddy", {} }, + .{ "gold", {} }, + .{ "goldpoint", {} }, + .{ "golf", {} }, + .{ "goo", {} }, + .{ "goodyear", {} }, + .{ "goog", {} }, + .{ "google", {} }, + .{ "gop", {} }, + .{ "got", {} }, + .{ "grainger", {} }, + .{ "graphics", {} }, + .{ "gratis", {} }, + .{ "green", {} }, + .{ "gripe", {} }, + .{ "grocery", {} }, + .{ "group", {} }, + .{ "gucci", {} }, + .{ "guge", {} }, + .{ "guide", {} }, + .{ "guitars", {} }, + .{ "guru", {} }, + .{ "hair", {} }, + .{ "hamburg", {} }, + .{ "hangout", {} }, + .{ "haus", {} }, + .{ "hbo", {} }, + .{ "hdfc", {} }, + .{ "hdfcbank", {} }, + .{ "health", {} }, + .{ "healthcare", {} }, + .{ "help", {} }, + .{ "helsinki", {} }, + .{ "here", {} }, + .{ "hermes", {} }, + .{ "hiphop", {} }, + .{ "hisamitsu", {} }, + .{ "hitachi", {} }, + .{ "hiv", {} }, + .{ "hkt", {} }, + .{ "hockey", {} }, + .{ "holdings", {} }, + .{ "holiday", {} }, + .{ "homedepot", {} }, + .{ "homegoods", {} }, + .{ "homes", {} }, + .{ "homesense", {} }, + .{ "honda", {} }, + .{ "horse", {} }, + .{ "hospital", {} }, + .{ "host", {} }, + .{ "hosting", {} }, + .{ "hot", {} }, + .{ "hotels", {} }, + .{ "hotmail", {} }, + .{ "house", {} }, + .{ "how", {} }, + .{ "hsbc", {} }, + .{ "hughes", {} }, + .{ "hyatt", {} }, + .{ "hyundai", {} }, + .{ "ibm", {} }, + .{ "icbc", {} }, + .{ "ice", {} }, + .{ "icu", {} }, + .{ "ieee", {} }, + .{ "ifm", {} }, + .{ "ikano", {} }, + .{ "imamat", {} }, + .{ "imdb", {} }, + .{ "immo", {} }, + .{ "immobilien", {} }, + .{ "inc", {} }, + .{ "industries", {} }, + .{ "infiniti", {} }, + .{ "ing", {} }, + .{ "ink", {} }, + .{ "institute", {} }, + .{ "insurance", {} }, + .{ "insure", {} }, + .{ "international", {} }, + .{ "intuit", {} }, + .{ "investments", {} }, + .{ "ipiranga", {} }, + .{ "irish", {} }, + .{ "ismaili", {} }, + .{ "ist", {} }, + .{ "istanbul", {} }, + .{ "itau", {} }, + .{ "itv", {} }, + .{ "jaguar", {} }, + .{ "java", {} }, + .{ "jcb", {} }, + .{ "jeep", {} }, + .{ "jetzt", {} }, + .{ "jewelry", {} }, + .{ "jio", {} }, + .{ "jll", {} }, + .{ "jmp", {} }, + .{ "jnj", {} }, + .{ "joburg", {} }, + .{ "jot", {} }, + .{ "joy", {} }, + .{ "jpmorgan", {} }, + .{ "jprs", {} }, + .{ "juegos", {} }, + .{ "juniper", {} }, + .{ "kaufen", {} }, + .{ "kddi", {} }, + .{ "kerryhotels", {} }, + .{ "kerrylogistics", {} }, + .{ "kerryproperties", {} }, + .{ "kfh", {} }, + .{ "kia", {} }, + .{ "kids", {} }, + .{ "kim", {} }, + .{ "kindle", {} }, + .{ "kitchen", {} }, + .{ "kiwi", {} }, + .{ "koeln", {} }, + .{ "komatsu", {} }, + .{ "kosher", {} }, + .{ "kpmg", {} }, + .{ "kpn", {} }, + .{ "krd", {} }, + .{ "kred", {} }, + .{ "kuokgroup", {} }, + .{ "kyoto", {} }, + .{ "lacaixa", {} }, + .{ "lamborghini", {} }, + .{ "lamer", {} }, + .{ "lancaster", {} }, + .{ "land", {} }, + .{ "landrover", {} }, + .{ "lanxess", {} }, + .{ "lasalle", {} }, + .{ "lat", {} }, + .{ "latino", {} }, + .{ "latrobe", {} }, + .{ "law", {} }, + .{ "lawyer", {} }, + .{ "lds", {} }, + .{ "lease", {} }, + .{ "leclerc", {} }, + .{ "lefrak", {} }, + .{ "legal", {} }, + .{ "lego", {} }, + .{ "lexus", {} }, + .{ "lgbt", {} }, + .{ "lidl", {} }, + .{ "life", {} }, + .{ "lifeinsurance", {} }, + .{ "lifestyle", {} }, + .{ "lighting", {} }, + .{ "like", {} }, + .{ "lilly", {} }, + .{ "limited", {} }, + .{ "limo", {} }, + .{ "lincoln", {} }, + .{ "link", {} }, + .{ "lipsy", {} }, + .{ "live", {} }, + .{ "living", {} }, + .{ "llc", {} }, + .{ "llp", {} }, + .{ "loan", {} }, + .{ "loans", {} }, + .{ "locker", {} }, + .{ "locus", {} }, + .{ "lol", {} }, + .{ "london", {} }, + .{ "lotte", {} }, + .{ "lotto", {} }, + .{ "love", {} }, + .{ "lpl", {} }, + .{ "lplfinancial", {} }, + .{ "ltd", {} }, + .{ "ltda", {} }, + .{ "lundbeck", {} }, + .{ "luxe", {} }, + .{ "luxury", {} }, + .{ "madrid", {} }, + .{ "maif", {} }, + .{ "maison", {} }, + .{ "makeup", {} }, + .{ "man", {} }, + .{ "management", {} }, + .{ "mango", {} }, + .{ "map", {} }, + .{ "market", {} }, + .{ "marketing", {} }, + .{ "markets", {} }, + .{ "marriott", {} }, + .{ "marshalls", {} }, + .{ "mattel", {} }, + .{ "mba", {} }, + .{ "mckinsey", {} }, + .{ "med", {} }, + .{ "media", {} }, + .{ "meet", {} }, + .{ "melbourne", {} }, + .{ "meme", {} }, + .{ "memorial", {} }, + .{ "men", {} }, + .{ "menu", {} }, + .{ "merck", {} }, + .{ "merckmsd", {} }, + .{ "miami", {} }, + .{ "microsoft", {} }, + .{ "mini", {} }, + .{ "mint", {} }, + .{ "mit", {} }, + .{ "mitsubishi", {} }, + .{ "mlb", {} }, + .{ "mls", {} }, + .{ "mma", {} }, + .{ "mobile", {} }, + .{ "moda", {} }, + .{ "moe", {} }, + .{ "moi", {} }, + .{ "mom", {} }, + .{ "monash", {} }, + .{ "money", {} }, + .{ "monster", {} }, + .{ "mormon", {} }, + .{ "mortgage", {} }, + .{ "moscow", {} }, + .{ "moto", {} }, + .{ "motorcycles", {} }, + .{ "mov", {} }, + .{ "movie", {} }, + .{ "msd", {} }, + .{ "mtn", {} }, + .{ "mtr", {} }, + .{ "music", {} }, + .{ "nab", {} }, + .{ "nagoya", {} }, + .{ "navy", {} }, + .{ "nba", {} }, + .{ "nec", {} }, + .{ "netbank", {} }, + .{ "netflix", {} }, + .{ "network", {} }, + .{ "neustar", {} }, + .{ "new", {} }, + .{ "news", {} }, + .{ "next", {} }, + .{ "nextdirect", {} }, + .{ "nexus", {} }, + .{ "nfl", {} }, + .{ "ngo", {} }, + .{ "nhk", {} }, + .{ "nico", {} }, + .{ "nike", {} }, + .{ "nikon", {} }, + .{ "ninja", {} }, + .{ "nissan", {} }, + .{ "nissay", {} }, + .{ "nokia", {} }, + .{ "norton", {} }, + .{ "now", {} }, + .{ "nowruz", {} }, + .{ "nowtv", {} }, + .{ "nra", {} }, + .{ "nrw", {} }, + .{ "ntt", {} }, + .{ "nyc", {} }, + .{ "obi", {} }, + .{ "observer", {} }, + .{ "office", {} }, + .{ "okinawa", {} }, + .{ "olayan", {} }, + .{ "olayangroup", {} }, + .{ "ollo", {} }, + .{ "omega", {} }, + .{ "one", {} }, + .{ "ong", {} }, + .{ "onl", {} }, + .{ "online", {} }, + .{ "ooo", {} }, + .{ "open", {} }, + .{ "oracle", {} }, + .{ "orange", {} }, + .{ "organic", {} }, + .{ "origins", {} }, + .{ "osaka", {} }, + .{ "otsuka", {} }, + .{ "ott", {} }, + .{ "ovh", {} }, + .{ "page", {} }, + .{ "panasonic", {} }, + .{ "paris", {} }, + .{ "pars", {} }, + .{ "partners", {} }, + .{ "parts", {} }, + .{ "party", {} }, + .{ "pay", {} }, + .{ "pccw", {} }, + .{ "pet", {} }, + .{ "pfizer", {} }, + .{ "pharmacy", {} }, + .{ "phd", {} }, + .{ "philips", {} }, + .{ "phone", {} }, + .{ "photo", {} }, + .{ "photography", {} }, + .{ "photos", {} }, + .{ "physio", {} }, + .{ "pics", {} }, + .{ "pictet", {} }, + .{ "pictures", {} }, + .{ "pid", {} }, + .{ "pin", {} }, + .{ "ping", {} }, + .{ "pink", {} }, + .{ "pioneer", {} }, + .{ "pizza", {} }, + .{ "place", {} }, + .{ "play", {} }, + .{ "playstation", {} }, + .{ "plumbing", {} }, + .{ "plus", {} }, + .{ "pnc", {} }, + .{ "pohl", {} }, + .{ "poker", {} }, + .{ "politie", {} }, + .{ "porn", {} }, + .{ "pramerica", {} }, + .{ "praxi", {} }, + .{ "press", {} }, + .{ "prime", {} }, + .{ "prod", {} }, + .{ "productions", {} }, + .{ "prof", {} }, + .{ "progressive", {} }, + .{ "promo", {} }, + .{ "properties", {} }, + .{ "property", {} }, + .{ "protection", {} }, + .{ "pru", {} }, + .{ "prudential", {} }, + .{ "pub", {} }, + .{ "pwc", {} }, + .{ "qpon", {} }, + .{ "quebec", {} }, + .{ "quest", {} }, + .{ "racing", {} }, + .{ "radio", {} }, + .{ "read", {} }, + .{ "realestate", {} }, + .{ "realtor", {} }, + .{ "realty", {} }, + .{ "recipes", {} }, + .{ "red", {} }, + .{ "redstone", {} }, + .{ "redumbrella", {} }, + .{ "rehab", {} }, + .{ "reise", {} }, + .{ "reisen", {} }, + .{ "reit", {} }, + .{ "reliance", {} }, + .{ "ren", {} }, + .{ "rent", {} }, + .{ "rentals", {} }, + .{ "repair", {} }, + .{ "report", {} }, + .{ "republican", {} }, + .{ "rest", {} }, + .{ "restaurant", {} }, + .{ "review", {} }, + .{ "reviews", {} }, + .{ "rexroth", {} }, + .{ "rich", {} }, + .{ "richardli", {} }, + .{ "ricoh", {} }, + .{ "ril", {} }, + .{ "rio", {} }, + .{ "rip", {} }, + .{ "rocks", {} }, + .{ "rodeo", {} }, + .{ "rogers", {} }, + .{ "room", {} }, + .{ "rsvp", {} }, + .{ "rugby", {} }, + .{ "ruhr", {} }, + .{ "run", {} }, + .{ "rwe", {} }, + .{ "ryukyu", {} }, + .{ "saarland", {} }, + .{ "safe", {} }, + .{ "safety", {} }, + .{ "sakura", {} }, + .{ "sale", {} }, + .{ "salon", {} }, + .{ "samsclub", {} }, + .{ "samsung", {} }, + .{ "sandvik", {} }, + .{ "sandvikcoromant", {} }, + .{ "sanofi", {} }, + .{ "sap", {} }, + .{ "sarl", {} }, + .{ "sas", {} }, + .{ "save", {} }, + .{ "saxo", {} }, + .{ "sbi", {} }, + .{ "sbs", {} }, + .{ "scb", {} }, + .{ "schaeffler", {} }, + .{ "schmidt", {} }, + .{ "scholarships", {} }, + .{ "school", {} }, + .{ "schule", {} }, + .{ "schwarz", {} }, + .{ "science", {} }, + .{ "scot", {} }, + .{ "search", {} }, + .{ "seat", {} }, + .{ "secure", {} }, + .{ "security", {} }, + .{ "seek", {} }, + .{ "select", {} }, + .{ "sener", {} }, + .{ "services", {} }, + .{ "seven", {} }, + .{ "sew", {} }, + .{ "sex", {} }, + .{ "sexy", {} }, + .{ "sfr", {} }, + .{ "shangrila", {} }, + .{ "sharp", {} }, + .{ "shell", {} }, + .{ "shia", {} }, + .{ "shiksha", {} }, + .{ "shoes", {} }, + .{ "shop", {} }, + .{ "shopping", {} }, + .{ "shouji", {} }, + .{ "show", {} }, + .{ "silk", {} }, + .{ "sina", {} }, + .{ "singles", {} }, + .{ "site", {} }, + .{ "ski", {} }, + .{ "skin", {} }, + .{ "sky", {} }, + .{ "skype", {} }, + .{ "sling", {} }, + .{ "smart", {} }, + .{ "smile", {} }, + .{ "sncf", {} }, + .{ "soccer", {} }, + .{ "social", {} }, + .{ "softbank", {} }, + .{ "software", {} }, + .{ "sohu", {} }, + .{ "solar", {} }, + .{ "solutions", {} }, + .{ "song", {} }, + .{ "sony", {} }, + .{ "soy", {} }, + .{ "spa", {} }, + .{ "space", {} }, + .{ "sport", {} }, + .{ "spot", {} }, + .{ "srl", {} }, + .{ "stada", {} }, + .{ "staples", {} }, + .{ "star", {} }, + .{ "statebank", {} }, + .{ "statefarm", {} }, + .{ "stc", {} }, + .{ "stcgroup", {} }, + .{ "stockholm", {} }, + .{ "storage", {} }, + .{ "store", {} }, + .{ "stream", {} }, + .{ "studio", {} }, + .{ "study", {} }, + .{ "style", {} }, + .{ "sucks", {} }, + .{ "supplies", {} }, + .{ "supply", {} }, + .{ "support", {} }, + .{ "surf", {} }, + .{ "surgery", {} }, + .{ "suzuki", {} }, + .{ "swatch", {} }, + .{ "swiss", {} }, + .{ "sydney", {} }, + .{ "systems", {} }, + .{ "tab", {} }, + .{ "taipei", {} }, + .{ "talk", {} }, + .{ "taobao", {} }, + .{ "target", {} }, + .{ "tatamotors", {} }, + .{ "tatar", {} }, + .{ "tattoo", {} }, + .{ "tax", {} }, + .{ "taxi", {} }, + .{ "tci", {} }, + .{ "tdk", {} }, + .{ "team", {} }, + .{ "tech", {} }, + .{ "technology", {} }, + .{ "temasek", {} }, + .{ "tennis", {} }, + .{ "teva", {} }, + .{ "thd", {} }, + .{ "theater", {} }, + .{ "theatre", {} }, + .{ "tiaa", {} }, + .{ "tickets", {} }, + .{ "tienda", {} }, + .{ "tips", {} }, + .{ "tires", {} }, + .{ "tirol", {} }, + .{ "tjmaxx", {} }, + .{ "tjx", {} }, + .{ "tkmaxx", {} }, + .{ "tmall", {} }, + .{ "today", {} }, + .{ "tokyo", {} }, + .{ "tools", {} }, + .{ "top", {} }, + .{ "toray", {} }, + .{ "toshiba", {} }, + .{ "total", {} }, + .{ "tours", {} }, + .{ "town", {} }, + .{ "toyota", {} }, + .{ "toys", {} }, + .{ "trade", {} }, + .{ "trading", {} }, + .{ "training", {} }, + .{ "travel", {} }, + .{ "travelers", {} }, + .{ "travelersinsurance", {} }, + .{ "trust", {} }, + .{ "trv", {} }, + .{ "tube", {} }, + .{ "tui", {} }, + .{ "tunes", {} }, + .{ "tushu", {} }, + .{ "tvs", {} }, + .{ "ubank", {} }, + .{ "ubs", {} }, + .{ "unicom", {} }, + .{ "university", {} }, + .{ "uno", {} }, + .{ "uol", {} }, + .{ "ups", {} }, + .{ "vacations", {} }, + .{ "vana", {} }, + .{ "vanguard", {} }, + .{ "vegas", {} }, + .{ "ventures", {} }, + .{ "verisign", {} }, + .{ "versicherung", {} }, + .{ "vet", {} }, + .{ "viajes", {} }, + .{ "video", {} }, + .{ "vig", {} }, + .{ "viking", {} }, + .{ "villas", {} }, + .{ "vin", {} }, + .{ "vip", {} }, + .{ "virgin", {} }, + .{ "visa", {} }, + .{ "vision", {} }, + .{ "viva", {} }, + .{ "vivo", {} }, + .{ "vlaanderen", {} }, + .{ "vodka", {} }, + .{ "volvo", {} }, + .{ "vote", {} }, + .{ "voting", {} }, + .{ "voto", {} }, + .{ "voyage", {} }, + .{ "wales", {} }, + .{ "walmart", {} }, + .{ "walter", {} }, + .{ "wang", {} }, + .{ "wanggou", {} }, + .{ "watch", {} }, + .{ "watches", {} }, + .{ "weather", {} }, + .{ "weatherchannel", {} }, + .{ "webcam", {} }, + .{ "weber", {} }, + .{ "website", {} }, + .{ "wed", {} }, + .{ "wedding", {} }, + .{ "weibo", {} }, + .{ "weir", {} }, + .{ "whoswho", {} }, + .{ "wien", {} }, + .{ "wiki", {} }, + .{ "williamhill", {} }, + .{ "win", {} }, + .{ "windows", {} }, + .{ "wine", {} }, + .{ "winners", {} }, + .{ "wme", {} }, + .{ "wolterskluwer", {} }, + .{ "woodside", {} }, + .{ "work", {} }, + .{ "works", {} }, + .{ "world", {} }, + .{ "wow", {} }, + .{ "wtc", {} }, + .{ "wtf", {} }, + .{ "xbox", {} }, + .{ "xerox", {} }, + .{ "xihuan", {} }, + .{ "xin", {} }, + .{ "कॉम", {} }, + .{ "セール", {} }, + .{ "佛山", {} }, + .{ "慈善", {} }, + .{ "集团", {} }, + .{ "在线", {} }, + .{ "点看", {} }, + .{ "คอม", {} }, + .{ "八卦", {} }, + .{ "موقع", {} }, + .{ "公益", {} }, + .{ "公司", {} }, + .{ "香格里拉", {} }, + .{ "网站", {} }, + .{ "移动", {} }, + .{ "我爱你", {} }, + .{ "москва", {} }, + .{ "католик", {} }, + .{ "онлайн", {} }, + .{ "сайт", {} }, + .{ "联通", {} }, + .{ "קום", {} }, + .{ "时尚", {} }, + .{ "微博", {} }, + .{ "淡马锡", {} }, + .{ "ファッション", {} }, + .{ "орг", {} }, + .{ "नेट", {} }, + .{ "ストア", {} }, + .{ "アマゾン", {} }, + .{ "삼성", {} }, + .{ "商标", {} }, + .{ "商店", {} }, + .{ "商城", {} }, + .{ "дети", {} }, + .{ "ポイント", {} }, + .{ "新闻", {} }, + .{ "家電", {} }, + .{ "كوم", {} }, + .{ "中文网", {} }, + .{ "中信", {} }, + .{ "娱乐", {} }, + .{ "谷歌", {} }, + .{ "電訊盈科", {} }, + .{ "购物", {} }, + .{ "クラウド", {} }, + .{ "通販", {} }, + .{ "网店", {} }, + .{ "संगठन", {} }, + .{ "餐厅", {} }, + .{ "网络", {} }, + .{ "ком", {} }, + .{ "亚马逊", {} }, + .{ "食品", {} }, + .{ "飞利浦", {} }, + .{ "手机", {} }, + .{ "ارامكو", {} }, + .{ "العليان", {} }, + .{ "بازار", {} }, + .{ "ابوظبي", {} }, + .{ "كاثوليك", {} }, + .{ "همراه", {} }, + .{ "닷컴", {} }, + .{ "政府", {} }, + .{ "شبكة", {} }, + .{ "بيتك", {} }, + .{ "عرب", {} }, + .{ "机构", {} }, + .{ "组织机构", {} }, + .{ "健康", {} }, + .{ "招聘", {} }, + .{ "рус", {} }, + .{ "大拿", {} }, + .{ "みんな", {} }, + .{ "グーグル", {} }, + .{ "世界", {} }, + .{ "書籍", {} }, + .{ "网址", {} }, + .{ "닷넷", {} }, + .{ "コム", {} }, + .{ "天主教", {} }, + .{ "游戏", {} }, + .{ "vermögensberater", {} }, + .{ "vermögensberatung", {} }, + .{ "企业", {} }, + .{ "信息", {} }, + .{ "嘉里大酒店", {} }, + .{ "嘉里", {} }, + .{ "广东", {} }, + .{ "政务", {} }, + .{ "xyz", {} }, + .{ "yachts", {} }, + .{ "yahoo", {} }, + .{ "yamaxun", {} }, + .{ "yandex", {} }, + .{ "yodobashi", {} }, + .{ "yoga", {} }, + .{ "yokohama", {} }, + .{ "you", {} }, + .{ "youtube", {} }, + .{ "yun", {} }, + .{ "zappos", {} }, + .{ "zara", {} }, + .{ "zero", {} }, + .{ "zip", {} }, + .{ "zone", {} }, + .{ "zuerich", {} }, + .{ "co.krd", {} }, + .{ "edu.krd", {} }, + .{ "art.pl", {} }, + .{ "gliwice.pl", {} }, + .{ "krakow.pl", {} }, + .{ "poznan.pl", {} }, + .{ "wroc.pl", {} }, + .{ "zakopane.pl", {} }, + .{ "lib.de.us", {} }, + .{ "12chars.dev", {} }, + .{ "12chars.it", {} }, + .{ "12chars.pro", {} }, + .{ "cc.ua", {} }, + .{ "inf.ua", {} }, + .{ "ltd.ua", {} }, + .{ "611.to", {} }, + .{ "a2hosted.com", {} }, + .{ "cpserver.com", {} }, + .{ "*.on-acorn.io", {} }, + .{ "activetrail.biz", {} }, + .{ "adaptable.app", {} }, + .{ "myaddr.dev", {} }, + .{ "myaddr.io", {} }, + .{ "dyn.addr.tools", {} }, + .{ "myaddr.tools", {} }, + .{ "adobeaemcloud.com", {} }, + .{ "*.dev.adobeaemcloud.com", {} }, + .{ "aem.live", {} }, + .{ "hlx.live", {} }, + .{ "adobeaemcloud.net", {} }, + .{ "aem.page", {} }, + .{ "hlx.page", {} }, + .{ "hlx3.page", {} }, + .{ "adobeio-static.net", {} }, + .{ "adobeioruntime.net", {} }, + .{ "africa.com", {} }, + .{ "beep.pl", {} }, + .{ "airkitapps.com", {} }, + .{ "airkitapps-au.com", {} }, + .{ "airkitapps.eu", {} }, + .{ "aiven.app", {} }, + .{ "aivencloud.com", {} }, + .{ "akadns.net", {} }, + .{ "akamai.net", {} }, + .{ "akamai-staging.net", {} }, + .{ "akamaiedge.net", {} }, + .{ "akamaiedge-staging.net", {} }, + .{ "akamaihd.net", {} }, + .{ "akamaihd-staging.net", {} }, + .{ "akamaiorigin.net", {} }, + .{ "akamaiorigin-staging.net", {} }, + .{ "akamaized.net", {} }, + .{ "akamaized-staging.net", {} }, + .{ "edgekey.net", {} }, + .{ "edgekey-staging.net", {} }, + .{ "edgesuite.net", {} }, + .{ "edgesuite-staging.net", {} }, + .{ "barsy.ca", {} }, + .{ "*.compute.estate", {} }, + .{ "*.alces.network", {} }, + .{ "alibabacloudcs.com", {} }, + .{ "kasserver.com", {} }, + .{ "altervista.org", {} }, + .{ "alwaysdata.net", {} }, + .{ "myamaze.net", {} }, + .{ "execute-api.cn-north-1.amazonaws.com.cn", {} }, + .{ "execute-api.cn-northwest-1.amazonaws.com.cn", {} }, + .{ "execute-api.af-south-1.amazonaws.com", {} }, + .{ "execute-api.ap-east-1.amazonaws.com", {} }, + .{ "execute-api.ap-northeast-1.amazonaws.com", {} }, + .{ "execute-api.ap-northeast-2.amazonaws.com", {} }, + .{ "execute-api.ap-northeast-3.amazonaws.com", {} }, + .{ "execute-api.ap-south-1.amazonaws.com", {} }, + .{ "execute-api.ap-south-2.amazonaws.com", {} }, + .{ "execute-api.ap-southeast-1.amazonaws.com", {} }, + .{ "execute-api.ap-southeast-2.amazonaws.com", {} }, + .{ "execute-api.ap-southeast-3.amazonaws.com", {} }, + .{ "execute-api.ap-southeast-4.amazonaws.com", {} }, + .{ "execute-api.ap-southeast-5.amazonaws.com", {} }, + .{ "execute-api.ca-central-1.amazonaws.com", {} }, + .{ "execute-api.ca-west-1.amazonaws.com", {} }, + .{ "execute-api.eu-central-1.amazonaws.com", {} }, + .{ "execute-api.eu-central-2.amazonaws.com", {} }, + .{ "execute-api.eu-north-1.amazonaws.com", {} }, + .{ "execute-api.eu-south-1.amazonaws.com", {} }, + .{ "execute-api.eu-south-2.amazonaws.com", {} }, + .{ "execute-api.eu-west-1.amazonaws.com", {} }, + .{ "execute-api.eu-west-2.amazonaws.com", {} }, + .{ "execute-api.eu-west-3.amazonaws.com", {} }, + .{ "execute-api.il-central-1.amazonaws.com", {} }, + .{ "execute-api.me-central-1.amazonaws.com", {} }, + .{ "execute-api.me-south-1.amazonaws.com", {} }, + .{ "execute-api.sa-east-1.amazonaws.com", {} }, + .{ "execute-api.us-east-1.amazonaws.com", {} }, + .{ "execute-api.us-east-2.amazonaws.com", {} }, + .{ "execute-api.us-gov-east-1.amazonaws.com", {} }, + .{ "execute-api.us-gov-west-1.amazonaws.com", {} }, + .{ "execute-api.us-west-1.amazonaws.com", {} }, + .{ "execute-api.us-west-2.amazonaws.com", {} }, + .{ "cloudfront.net", {} }, + .{ "auth.af-south-1.amazoncognito.com", {} }, + .{ "auth.ap-east-1.amazoncognito.com", {} }, + .{ "auth.ap-northeast-1.amazoncognito.com", {} }, + .{ "auth.ap-northeast-2.amazoncognito.com", {} }, + .{ "auth.ap-northeast-3.amazoncognito.com", {} }, + .{ "auth.ap-south-1.amazoncognito.com", {} }, + .{ "auth.ap-south-2.amazoncognito.com", {} }, + .{ "auth.ap-southeast-1.amazoncognito.com", {} }, + .{ "auth.ap-southeast-2.amazoncognito.com", {} }, + .{ "auth.ap-southeast-3.amazoncognito.com", {} }, + .{ "auth.ap-southeast-4.amazoncognito.com", {} }, + .{ "auth.ca-central-1.amazoncognito.com", {} }, + .{ "auth.ca-west-1.amazoncognito.com", {} }, + .{ "auth.eu-central-1.amazoncognito.com", {} }, + .{ "auth.eu-central-2.amazoncognito.com", {} }, + .{ "auth.eu-north-1.amazoncognito.com", {} }, + .{ "auth.eu-south-1.amazoncognito.com", {} }, + .{ "auth.eu-south-2.amazoncognito.com", {} }, + .{ "auth.eu-west-1.amazoncognito.com", {} }, + .{ "auth.eu-west-2.amazoncognito.com", {} }, + .{ "auth.eu-west-3.amazoncognito.com", {} }, + .{ "auth.il-central-1.amazoncognito.com", {} }, + .{ "auth.me-central-1.amazoncognito.com", {} }, + .{ "auth.me-south-1.amazoncognito.com", {} }, + .{ "auth.sa-east-1.amazoncognito.com", {} }, + .{ "auth.us-east-1.amazoncognito.com", {} }, + .{ "auth-fips.us-east-1.amazoncognito.com", {} }, + .{ "auth.us-east-2.amazoncognito.com", {} }, + .{ "auth-fips.us-east-2.amazoncognito.com", {} }, + .{ "auth-fips.us-gov-west-1.amazoncognito.com", {} }, + .{ "auth.us-west-1.amazoncognito.com", {} }, + .{ "auth-fips.us-west-1.amazoncognito.com", {} }, + .{ "auth.us-west-2.amazoncognito.com", {} }, + .{ "auth-fips.us-west-2.amazoncognito.com", {} }, + .{ "*.compute.amazonaws.com.cn", {} }, + .{ "*.compute.amazonaws.com", {} }, + .{ "*.compute-1.amazonaws.com", {} }, + .{ "us-east-1.amazonaws.com", {} }, + .{ "emrappui-prod.cn-north-1.amazonaws.com.cn", {} }, + .{ "emrnotebooks-prod.cn-north-1.amazonaws.com.cn", {} }, + .{ "emrstudio-prod.cn-north-1.amazonaws.com.cn", {} }, + .{ "emrappui-prod.cn-northwest-1.amazonaws.com.cn", {} }, + .{ "emrnotebooks-prod.cn-northwest-1.amazonaws.com.cn", {} }, + .{ "emrstudio-prod.cn-northwest-1.amazonaws.com.cn", {} }, + .{ "emrappui-prod.af-south-1.amazonaws.com", {} }, + .{ "emrnotebooks-prod.af-south-1.amazonaws.com", {} }, + .{ "emrstudio-prod.af-south-1.amazonaws.com", {} }, + .{ "emrappui-prod.ap-east-1.amazonaws.com", {} }, + .{ "emrnotebooks-prod.ap-east-1.amazonaws.com", {} }, + .{ "emrstudio-prod.ap-east-1.amazonaws.com", {} }, + .{ "emrappui-prod.ap-northeast-1.amazonaws.com", {} }, + .{ "emrnotebooks-prod.ap-northeast-1.amazonaws.com", {} }, + .{ "emrstudio-prod.ap-northeast-1.amazonaws.com", {} }, + .{ "emrappui-prod.ap-northeast-2.amazonaws.com", {} }, + .{ "emrnotebooks-prod.ap-northeast-2.amazonaws.com", {} }, + .{ "emrstudio-prod.ap-northeast-2.amazonaws.com", {} }, + .{ "emrappui-prod.ap-northeast-3.amazonaws.com", {} }, + .{ "emrnotebooks-prod.ap-northeast-3.amazonaws.com", {} }, + .{ "emrstudio-prod.ap-northeast-3.amazonaws.com", {} }, + .{ "emrappui-prod.ap-south-1.amazonaws.com", {} }, + .{ "emrnotebooks-prod.ap-south-1.amazonaws.com", {} }, + .{ "emrstudio-prod.ap-south-1.amazonaws.com", {} }, + .{ "emrappui-prod.ap-south-2.amazonaws.com", {} }, + .{ "emrnotebooks-prod.ap-south-2.amazonaws.com", {} }, + .{ "emrstudio-prod.ap-south-2.amazonaws.com", {} }, + .{ "emrappui-prod.ap-southeast-1.amazonaws.com", {} }, + .{ "emrnotebooks-prod.ap-southeast-1.amazonaws.com", {} }, + .{ "emrstudio-prod.ap-southeast-1.amazonaws.com", {} }, + .{ "emrappui-prod.ap-southeast-2.amazonaws.com", {} }, + .{ "emrnotebooks-prod.ap-southeast-2.amazonaws.com", {} }, + .{ "emrstudio-prod.ap-southeast-2.amazonaws.com", {} }, + .{ "emrappui-prod.ap-southeast-3.amazonaws.com", {} }, + .{ "emrnotebooks-prod.ap-southeast-3.amazonaws.com", {} }, + .{ "emrstudio-prod.ap-southeast-3.amazonaws.com", {} }, + .{ "emrappui-prod.ap-southeast-4.amazonaws.com", {} }, + .{ "emrnotebooks-prod.ap-southeast-4.amazonaws.com", {} }, + .{ "emrstudio-prod.ap-southeast-4.amazonaws.com", {} }, + .{ "emrappui-prod.ca-central-1.amazonaws.com", {} }, + .{ "emrnotebooks-prod.ca-central-1.amazonaws.com", {} }, + .{ "emrstudio-prod.ca-central-1.amazonaws.com", {} }, + .{ "emrappui-prod.ca-west-1.amazonaws.com", {} }, + .{ "emrnotebooks-prod.ca-west-1.amazonaws.com", {} }, + .{ "emrstudio-prod.ca-west-1.amazonaws.com", {} }, + .{ "emrappui-prod.eu-central-1.amazonaws.com", {} }, + .{ "emrnotebooks-prod.eu-central-1.amazonaws.com", {} }, + .{ "emrstudio-prod.eu-central-1.amazonaws.com", {} }, + .{ "emrappui-prod.eu-central-2.amazonaws.com", {} }, + .{ "emrnotebooks-prod.eu-central-2.amazonaws.com", {} }, + .{ "emrstudio-prod.eu-central-2.amazonaws.com", {} }, + .{ "emrappui-prod.eu-north-1.amazonaws.com", {} }, + .{ "emrnotebooks-prod.eu-north-1.amazonaws.com", {} }, + .{ "emrstudio-prod.eu-north-1.amazonaws.com", {} }, + .{ "emrappui-prod.eu-south-1.amazonaws.com", {} }, + .{ "emrnotebooks-prod.eu-south-1.amazonaws.com", {} }, + .{ "emrstudio-prod.eu-south-1.amazonaws.com", {} }, + .{ "emrappui-prod.eu-south-2.amazonaws.com", {} }, + .{ "emrnotebooks-prod.eu-south-2.amazonaws.com", {} }, + .{ "emrstudio-prod.eu-south-2.amazonaws.com", {} }, + .{ "emrappui-prod.eu-west-1.amazonaws.com", {} }, + .{ "emrnotebooks-prod.eu-west-1.amazonaws.com", {} }, + .{ "emrstudio-prod.eu-west-1.amazonaws.com", {} }, + .{ "emrappui-prod.eu-west-2.amazonaws.com", {} }, + .{ "emrnotebooks-prod.eu-west-2.amazonaws.com", {} }, + .{ "emrstudio-prod.eu-west-2.amazonaws.com", {} }, + .{ "emrappui-prod.eu-west-3.amazonaws.com", {} }, + .{ "emrnotebooks-prod.eu-west-3.amazonaws.com", {} }, + .{ "emrstudio-prod.eu-west-3.amazonaws.com", {} }, + .{ "emrappui-prod.il-central-1.amazonaws.com", {} }, + .{ "emrnotebooks-prod.il-central-1.amazonaws.com", {} }, + .{ "emrstudio-prod.il-central-1.amazonaws.com", {} }, + .{ "emrappui-prod.me-central-1.amazonaws.com", {} }, + .{ "emrnotebooks-prod.me-central-1.amazonaws.com", {} }, + .{ "emrstudio-prod.me-central-1.amazonaws.com", {} }, + .{ "emrappui-prod.me-south-1.amazonaws.com", {} }, + .{ "emrnotebooks-prod.me-south-1.amazonaws.com", {} }, + .{ "emrstudio-prod.me-south-1.amazonaws.com", {} }, + .{ "emrappui-prod.sa-east-1.amazonaws.com", {} }, + .{ "emrnotebooks-prod.sa-east-1.amazonaws.com", {} }, + .{ "emrstudio-prod.sa-east-1.amazonaws.com", {} }, + .{ "emrappui-prod.us-east-1.amazonaws.com", {} }, + .{ "emrnotebooks-prod.us-east-1.amazonaws.com", {} }, + .{ "emrstudio-prod.us-east-1.amazonaws.com", {} }, + .{ "emrappui-prod.us-east-2.amazonaws.com", {} }, + .{ "emrnotebooks-prod.us-east-2.amazonaws.com", {} }, + .{ "emrstudio-prod.us-east-2.amazonaws.com", {} }, + .{ "emrappui-prod.us-gov-east-1.amazonaws.com", {} }, + .{ "emrnotebooks-prod.us-gov-east-1.amazonaws.com", {} }, + .{ "emrstudio-prod.us-gov-east-1.amazonaws.com", {} }, + .{ "emrappui-prod.us-gov-west-1.amazonaws.com", {} }, + .{ "emrnotebooks-prod.us-gov-west-1.amazonaws.com", {} }, + .{ "emrstudio-prod.us-gov-west-1.amazonaws.com", {} }, + .{ "emrappui-prod.us-west-1.amazonaws.com", {} }, + .{ "emrnotebooks-prod.us-west-1.amazonaws.com", {} }, + .{ "emrstudio-prod.us-west-1.amazonaws.com", {} }, + .{ "emrappui-prod.us-west-2.amazonaws.com", {} }, + .{ "emrnotebooks-prod.us-west-2.amazonaws.com", {} }, + .{ "emrstudio-prod.us-west-2.amazonaws.com", {} }, + .{ "*.cn-north-1.airflow.amazonaws.com.cn", {} }, + .{ "*.cn-northwest-1.airflow.amazonaws.com.cn", {} }, + .{ "*.af-south-1.airflow.amazonaws.com", {} }, + .{ "*.ap-east-1.airflow.amazonaws.com", {} }, + .{ "*.ap-northeast-1.airflow.amazonaws.com", {} }, + .{ "*.ap-northeast-2.airflow.amazonaws.com", {} }, + .{ "*.ap-northeast-3.airflow.amazonaws.com", {} }, + .{ "*.ap-south-1.airflow.amazonaws.com", {} }, + .{ "*.ap-south-2.airflow.amazonaws.com", {} }, + .{ "*.ap-southeast-1.airflow.amazonaws.com", {} }, + .{ "*.ap-southeast-2.airflow.amazonaws.com", {} }, + .{ "*.ap-southeast-3.airflow.amazonaws.com", {} }, + .{ "*.ap-southeast-4.airflow.amazonaws.com", {} }, + .{ "*.ca-central-1.airflow.amazonaws.com", {} }, + .{ "*.ca-west-1.airflow.amazonaws.com", {} }, + .{ "*.eu-central-1.airflow.amazonaws.com", {} }, + .{ "*.eu-central-2.airflow.amazonaws.com", {} }, + .{ "*.eu-north-1.airflow.amazonaws.com", {} }, + .{ "*.eu-south-1.airflow.amazonaws.com", {} }, + .{ "*.eu-south-2.airflow.amazonaws.com", {} }, + .{ "*.eu-west-1.airflow.amazonaws.com", {} }, + .{ "*.eu-west-2.airflow.amazonaws.com", {} }, + .{ "*.eu-west-3.airflow.amazonaws.com", {} }, + .{ "*.il-central-1.airflow.amazonaws.com", {} }, + .{ "*.me-central-1.airflow.amazonaws.com", {} }, + .{ "*.me-south-1.airflow.amazonaws.com", {} }, + .{ "*.sa-east-1.airflow.amazonaws.com", {} }, + .{ "*.us-east-1.airflow.amazonaws.com", {} }, + .{ "*.us-east-2.airflow.amazonaws.com", {} }, + .{ "*.us-west-1.airflow.amazonaws.com", {} }, + .{ "*.us-west-2.airflow.amazonaws.com", {} }, + .{ "s3.dualstack.cn-north-1.amazonaws.com.cn", {} }, + .{ "s3-accesspoint.dualstack.cn-north-1.amazonaws.com.cn", {} }, + .{ "s3-website.dualstack.cn-north-1.amazonaws.com.cn", {} }, + .{ "s3.cn-north-1.amazonaws.com.cn", {} }, + .{ "s3-accesspoint.cn-north-1.amazonaws.com.cn", {} }, + .{ "s3-deprecated.cn-north-1.amazonaws.com.cn", {} }, + .{ "s3-object-lambda.cn-north-1.amazonaws.com.cn", {} }, + .{ "s3-website.cn-north-1.amazonaws.com.cn", {} }, + .{ "s3.dualstack.cn-northwest-1.amazonaws.com.cn", {} }, + .{ "s3-accesspoint.dualstack.cn-northwest-1.amazonaws.com.cn", {} }, + .{ "s3.cn-northwest-1.amazonaws.com.cn", {} }, + .{ "s3-accesspoint.cn-northwest-1.amazonaws.com.cn", {} }, + .{ "s3-object-lambda.cn-northwest-1.amazonaws.com.cn", {} }, + .{ "s3-website.cn-northwest-1.amazonaws.com.cn", {} }, + .{ "s3.dualstack.af-south-1.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.af-south-1.amazonaws.com", {} }, + .{ "s3-website.dualstack.af-south-1.amazonaws.com", {} }, + .{ "s3.af-south-1.amazonaws.com", {} }, + .{ "s3-accesspoint.af-south-1.amazonaws.com", {} }, + .{ "s3-object-lambda.af-south-1.amazonaws.com", {} }, + .{ "s3-website.af-south-1.amazonaws.com", {} }, + .{ "s3.dualstack.ap-east-1.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.ap-east-1.amazonaws.com", {} }, + .{ "s3.ap-east-1.amazonaws.com", {} }, + .{ "s3-accesspoint.ap-east-1.amazonaws.com", {} }, + .{ "s3-object-lambda.ap-east-1.amazonaws.com", {} }, + .{ "s3-website.ap-east-1.amazonaws.com", {} }, + .{ "s3.dualstack.ap-northeast-1.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.ap-northeast-1.amazonaws.com", {} }, + .{ "s3-website.dualstack.ap-northeast-1.amazonaws.com", {} }, + .{ "s3.ap-northeast-1.amazonaws.com", {} }, + .{ "s3-accesspoint.ap-northeast-1.amazonaws.com", {} }, + .{ "s3-object-lambda.ap-northeast-1.amazonaws.com", {} }, + .{ "s3-website.ap-northeast-1.amazonaws.com", {} }, + .{ "s3.dualstack.ap-northeast-2.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.ap-northeast-2.amazonaws.com", {} }, + .{ "s3-website.dualstack.ap-northeast-2.amazonaws.com", {} }, + .{ "s3.ap-northeast-2.amazonaws.com", {} }, + .{ "s3-accesspoint.ap-northeast-2.amazonaws.com", {} }, + .{ "s3-object-lambda.ap-northeast-2.amazonaws.com", {} }, + .{ "s3-website.ap-northeast-2.amazonaws.com", {} }, + .{ "s3.dualstack.ap-northeast-3.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.ap-northeast-3.amazonaws.com", {} }, + .{ "s3-website.dualstack.ap-northeast-3.amazonaws.com", {} }, + .{ "s3.ap-northeast-3.amazonaws.com", {} }, + .{ "s3-accesspoint.ap-northeast-3.amazonaws.com", {} }, + .{ "s3-object-lambda.ap-northeast-3.amazonaws.com", {} }, + .{ "s3-website.ap-northeast-3.amazonaws.com", {} }, + .{ "s3.dualstack.ap-south-1.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.ap-south-1.amazonaws.com", {} }, + .{ "s3-website.dualstack.ap-south-1.amazonaws.com", {} }, + .{ "s3.ap-south-1.amazonaws.com", {} }, + .{ "s3-accesspoint.ap-south-1.amazonaws.com", {} }, + .{ "s3-object-lambda.ap-south-1.amazonaws.com", {} }, + .{ "s3-website.ap-south-1.amazonaws.com", {} }, + .{ "s3.dualstack.ap-south-2.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.ap-south-2.amazonaws.com", {} }, + .{ "s3-website.dualstack.ap-south-2.amazonaws.com", {} }, + .{ "s3.ap-south-2.amazonaws.com", {} }, + .{ "s3-accesspoint.ap-south-2.amazonaws.com", {} }, + .{ "s3-object-lambda.ap-south-2.amazonaws.com", {} }, + .{ "s3-website.ap-south-2.amazonaws.com", {} }, + .{ "s3.dualstack.ap-southeast-1.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.ap-southeast-1.amazonaws.com", {} }, + .{ "s3-website.dualstack.ap-southeast-1.amazonaws.com", {} }, + .{ "s3.ap-southeast-1.amazonaws.com", {} }, + .{ "s3-accesspoint.ap-southeast-1.amazonaws.com", {} }, + .{ "s3-object-lambda.ap-southeast-1.amazonaws.com", {} }, + .{ "s3-website.ap-southeast-1.amazonaws.com", {} }, + .{ "s3.dualstack.ap-southeast-2.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.ap-southeast-2.amazonaws.com", {} }, + .{ "s3-website.dualstack.ap-southeast-2.amazonaws.com", {} }, + .{ "s3.ap-southeast-2.amazonaws.com", {} }, + .{ "s3-accesspoint.ap-southeast-2.amazonaws.com", {} }, + .{ "s3-object-lambda.ap-southeast-2.amazonaws.com", {} }, + .{ "s3-website.ap-southeast-2.amazonaws.com", {} }, + .{ "s3.dualstack.ap-southeast-3.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.ap-southeast-3.amazonaws.com", {} }, + .{ "s3-website.dualstack.ap-southeast-3.amazonaws.com", {} }, + .{ "s3.ap-southeast-3.amazonaws.com", {} }, + .{ "s3-accesspoint.ap-southeast-3.amazonaws.com", {} }, + .{ "s3-object-lambda.ap-southeast-3.amazonaws.com", {} }, + .{ "s3-website.ap-southeast-3.amazonaws.com", {} }, + .{ "s3.dualstack.ap-southeast-4.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.ap-southeast-4.amazonaws.com", {} }, + .{ "s3-website.dualstack.ap-southeast-4.amazonaws.com", {} }, + .{ "s3.ap-southeast-4.amazonaws.com", {} }, + .{ "s3-accesspoint.ap-southeast-4.amazonaws.com", {} }, + .{ "s3-object-lambda.ap-southeast-4.amazonaws.com", {} }, + .{ "s3-website.ap-southeast-4.amazonaws.com", {} }, + .{ "s3.dualstack.ap-southeast-5.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.ap-southeast-5.amazonaws.com", {} }, + .{ "s3-website.dualstack.ap-southeast-5.amazonaws.com", {} }, + .{ "s3.ap-southeast-5.amazonaws.com", {} }, + .{ "s3-accesspoint.ap-southeast-5.amazonaws.com", {} }, + .{ "s3-deprecated.ap-southeast-5.amazonaws.com", {} }, + .{ "s3-object-lambda.ap-southeast-5.amazonaws.com", {} }, + .{ "s3-website.ap-southeast-5.amazonaws.com", {} }, + .{ "s3.dualstack.ca-central-1.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.ca-central-1.amazonaws.com", {} }, + .{ "s3-accesspoint-fips.dualstack.ca-central-1.amazonaws.com", {} }, + .{ "s3-fips.dualstack.ca-central-1.amazonaws.com", {} }, + .{ "s3-website.dualstack.ca-central-1.amazonaws.com", {} }, + .{ "s3.ca-central-1.amazonaws.com", {} }, + .{ "s3-accesspoint.ca-central-1.amazonaws.com", {} }, + .{ "s3-accesspoint-fips.ca-central-1.amazonaws.com", {} }, + .{ "s3-fips.ca-central-1.amazonaws.com", {} }, + .{ "s3-object-lambda.ca-central-1.amazonaws.com", {} }, + .{ "s3-website.ca-central-1.amazonaws.com", {} }, + .{ "s3.dualstack.ca-west-1.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.ca-west-1.amazonaws.com", {} }, + .{ "s3-accesspoint-fips.dualstack.ca-west-1.amazonaws.com", {} }, + .{ "s3-fips.dualstack.ca-west-1.amazonaws.com", {} }, + .{ "s3-website.dualstack.ca-west-1.amazonaws.com", {} }, + .{ "s3.ca-west-1.amazonaws.com", {} }, + .{ "s3-accesspoint.ca-west-1.amazonaws.com", {} }, + .{ "s3-accesspoint-fips.ca-west-1.amazonaws.com", {} }, + .{ "s3-fips.ca-west-1.amazonaws.com", {} }, + .{ "s3-object-lambda.ca-west-1.amazonaws.com", {} }, + .{ "s3-website.ca-west-1.amazonaws.com", {} }, + .{ "s3.dualstack.eu-central-1.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.eu-central-1.amazonaws.com", {} }, + .{ "s3-website.dualstack.eu-central-1.amazonaws.com", {} }, + .{ "s3.eu-central-1.amazonaws.com", {} }, + .{ "s3-accesspoint.eu-central-1.amazonaws.com", {} }, + .{ "s3-object-lambda.eu-central-1.amazonaws.com", {} }, + .{ "s3-website.eu-central-1.amazonaws.com", {} }, + .{ "s3.dualstack.eu-central-2.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.eu-central-2.amazonaws.com", {} }, + .{ "s3-website.dualstack.eu-central-2.amazonaws.com", {} }, + .{ "s3.eu-central-2.amazonaws.com", {} }, + .{ "s3-accesspoint.eu-central-2.amazonaws.com", {} }, + .{ "s3-object-lambda.eu-central-2.amazonaws.com", {} }, + .{ "s3-website.eu-central-2.amazonaws.com", {} }, + .{ "s3.dualstack.eu-north-1.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.eu-north-1.amazonaws.com", {} }, + .{ "s3.eu-north-1.amazonaws.com", {} }, + .{ "s3-accesspoint.eu-north-1.amazonaws.com", {} }, + .{ "s3-object-lambda.eu-north-1.amazonaws.com", {} }, + .{ "s3-website.eu-north-1.amazonaws.com", {} }, + .{ "s3.dualstack.eu-south-1.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.eu-south-1.amazonaws.com", {} }, + .{ "s3-website.dualstack.eu-south-1.amazonaws.com", {} }, + .{ "s3.eu-south-1.amazonaws.com", {} }, + .{ "s3-accesspoint.eu-south-1.amazonaws.com", {} }, + .{ "s3-object-lambda.eu-south-1.amazonaws.com", {} }, + .{ "s3-website.eu-south-1.amazonaws.com", {} }, + .{ "s3.dualstack.eu-south-2.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.eu-south-2.amazonaws.com", {} }, + .{ "s3-website.dualstack.eu-south-2.amazonaws.com", {} }, + .{ "s3.eu-south-2.amazonaws.com", {} }, + .{ "s3-accesspoint.eu-south-2.amazonaws.com", {} }, + .{ "s3-object-lambda.eu-south-2.amazonaws.com", {} }, + .{ "s3-website.eu-south-2.amazonaws.com", {} }, + .{ "s3.dualstack.eu-west-1.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.eu-west-1.amazonaws.com", {} }, + .{ "s3-website.dualstack.eu-west-1.amazonaws.com", {} }, + .{ "s3.eu-west-1.amazonaws.com", {} }, + .{ "s3-accesspoint.eu-west-1.amazonaws.com", {} }, + .{ "s3-deprecated.eu-west-1.amazonaws.com", {} }, + .{ "s3-object-lambda.eu-west-1.amazonaws.com", {} }, + .{ "s3-website.eu-west-1.amazonaws.com", {} }, + .{ "s3.dualstack.eu-west-2.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.eu-west-2.amazonaws.com", {} }, + .{ "s3.eu-west-2.amazonaws.com", {} }, + .{ "s3-accesspoint.eu-west-2.amazonaws.com", {} }, + .{ "s3-object-lambda.eu-west-2.amazonaws.com", {} }, + .{ "s3-website.eu-west-2.amazonaws.com", {} }, + .{ "s3.dualstack.eu-west-3.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.eu-west-3.amazonaws.com", {} }, + .{ "s3-website.dualstack.eu-west-3.amazonaws.com", {} }, + .{ "s3.eu-west-3.amazonaws.com", {} }, + .{ "s3-accesspoint.eu-west-3.amazonaws.com", {} }, + .{ "s3-object-lambda.eu-west-3.amazonaws.com", {} }, + .{ "s3-website.eu-west-3.amazonaws.com", {} }, + .{ "s3.dualstack.il-central-1.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.il-central-1.amazonaws.com", {} }, + .{ "s3-website.dualstack.il-central-1.amazonaws.com", {} }, + .{ "s3.il-central-1.amazonaws.com", {} }, + .{ "s3-accesspoint.il-central-1.amazonaws.com", {} }, + .{ "s3-object-lambda.il-central-1.amazonaws.com", {} }, + .{ "s3-website.il-central-1.amazonaws.com", {} }, + .{ "s3.dualstack.me-central-1.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.me-central-1.amazonaws.com", {} }, + .{ "s3-website.dualstack.me-central-1.amazonaws.com", {} }, + .{ "s3.me-central-1.amazonaws.com", {} }, + .{ "s3-accesspoint.me-central-1.amazonaws.com", {} }, + .{ "s3-object-lambda.me-central-1.amazonaws.com", {} }, + .{ "s3-website.me-central-1.amazonaws.com", {} }, + .{ "s3.dualstack.me-south-1.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.me-south-1.amazonaws.com", {} }, + .{ "s3.me-south-1.amazonaws.com", {} }, + .{ "s3-accesspoint.me-south-1.amazonaws.com", {} }, + .{ "s3-object-lambda.me-south-1.amazonaws.com", {} }, + .{ "s3-website.me-south-1.amazonaws.com", {} }, + .{ "s3.amazonaws.com", {} }, + .{ "s3-1.amazonaws.com", {} }, + .{ "s3-ap-east-1.amazonaws.com", {} }, + .{ "s3-ap-northeast-1.amazonaws.com", {} }, + .{ "s3-ap-northeast-2.amazonaws.com", {} }, + .{ "s3-ap-northeast-3.amazonaws.com", {} }, + .{ "s3-ap-south-1.amazonaws.com", {} }, + .{ "s3-ap-southeast-1.amazonaws.com", {} }, + .{ "s3-ap-southeast-2.amazonaws.com", {} }, + .{ "s3-ca-central-1.amazonaws.com", {} }, + .{ "s3-eu-central-1.amazonaws.com", {} }, + .{ "s3-eu-north-1.amazonaws.com", {} }, + .{ "s3-eu-west-1.amazonaws.com", {} }, + .{ "s3-eu-west-2.amazonaws.com", {} }, + .{ "s3-eu-west-3.amazonaws.com", {} }, + .{ "s3-external-1.amazonaws.com", {} }, + .{ "s3-fips-us-gov-east-1.amazonaws.com", {} }, + .{ "s3-fips-us-gov-west-1.amazonaws.com", {} }, + .{ "mrap.accesspoint.s3-global.amazonaws.com", {} }, + .{ "s3-me-south-1.amazonaws.com", {} }, + .{ "s3-sa-east-1.amazonaws.com", {} }, + .{ "s3-us-east-2.amazonaws.com", {} }, + .{ "s3-us-gov-east-1.amazonaws.com", {} }, + .{ "s3-us-gov-west-1.amazonaws.com", {} }, + .{ "s3-us-west-1.amazonaws.com", {} }, + .{ "s3-us-west-2.amazonaws.com", {} }, + .{ "s3-website-ap-northeast-1.amazonaws.com", {} }, + .{ "s3-website-ap-southeast-1.amazonaws.com", {} }, + .{ "s3-website-ap-southeast-2.amazonaws.com", {} }, + .{ "s3-website-eu-west-1.amazonaws.com", {} }, + .{ "s3-website-sa-east-1.amazonaws.com", {} }, + .{ "s3-website-us-east-1.amazonaws.com", {} }, + .{ "s3-website-us-gov-west-1.amazonaws.com", {} }, + .{ "s3-website-us-west-1.amazonaws.com", {} }, + .{ "s3-website-us-west-2.amazonaws.com", {} }, + .{ "s3.dualstack.sa-east-1.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.sa-east-1.amazonaws.com", {} }, + .{ "s3-website.dualstack.sa-east-1.amazonaws.com", {} }, + .{ "s3.sa-east-1.amazonaws.com", {} }, + .{ "s3-accesspoint.sa-east-1.amazonaws.com", {} }, + .{ "s3-object-lambda.sa-east-1.amazonaws.com", {} }, + .{ "s3-website.sa-east-1.amazonaws.com", {} }, + .{ "s3.dualstack.us-east-1.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.us-east-1.amazonaws.com", {} }, + .{ "s3-accesspoint-fips.dualstack.us-east-1.amazonaws.com", {} }, + .{ "s3-fips.dualstack.us-east-1.amazonaws.com", {} }, + .{ "s3-website.dualstack.us-east-1.amazonaws.com", {} }, + .{ "s3.us-east-1.amazonaws.com", {} }, + .{ "s3-accesspoint.us-east-1.amazonaws.com", {} }, + .{ "s3-accesspoint-fips.us-east-1.amazonaws.com", {} }, + .{ "s3-deprecated.us-east-1.amazonaws.com", {} }, + .{ "s3-fips.us-east-1.amazonaws.com", {} }, + .{ "s3-object-lambda.us-east-1.amazonaws.com", {} }, + .{ "s3-website.us-east-1.amazonaws.com", {} }, + .{ "s3.dualstack.us-east-2.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.us-east-2.amazonaws.com", {} }, + .{ "s3-accesspoint-fips.dualstack.us-east-2.amazonaws.com", {} }, + .{ "s3-fips.dualstack.us-east-2.amazonaws.com", {} }, + .{ "s3-website.dualstack.us-east-2.amazonaws.com", {} }, + .{ "s3.us-east-2.amazonaws.com", {} }, + .{ "s3-accesspoint.us-east-2.amazonaws.com", {} }, + .{ "s3-accesspoint-fips.us-east-2.amazonaws.com", {} }, + .{ "s3-deprecated.us-east-2.amazonaws.com", {} }, + .{ "s3-fips.us-east-2.amazonaws.com", {} }, + .{ "s3-object-lambda.us-east-2.amazonaws.com", {} }, + .{ "s3-website.us-east-2.amazonaws.com", {} }, + .{ "s3.dualstack.us-gov-east-1.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.us-gov-east-1.amazonaws.com", {} }, + .{ "s3-accesspoint-fips.dualstack.us-gov-east-1.amazonaws.com", {} }, + .{ "s3-fips.dualstack.us-gov-east-1.amazonaws.com", {} }, + .{ "s3.us-gov-east-1.amazonaws.com", {} }, + .{ "s3-accesspoint.us-gov-east-1.amazonaws.com", {} }, + .{ "s3-accesspoint-fips.us-gov-east-1.amazonaws.com", {} }, + .{ "s3-fips.us-gov-east-1.amazonaws.com", {} }, + .{ "s3-object-lambda.us-gov-east-1.amazonaws.com", {} }, + .{ "s3-website.us-gov-east-1.amazonaws.com", {} }, + .{ "s3.dualstack.us-gov-west-1.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.us-gov-west-1.amazonaws.com", {} }, + .{ "s3-accesspoint-fips.dualstack.us-gov-west-1.amazonaws.com", {} }, + .{ "s3-fips.dualstack.us-gov-west-1.amazonaws.com", {} }, + .{ "s3.us-gov-west-1.amazonaws.com", {} }, + .{ "s3-accesspoint.us-gov-west-1.amazonaws.com", {} }, + .{ "s3-accesspoint-fips.us-gov-west-1.amazonaws.com", {} }, + .{ "s3-fips.us-gov-west-1.amazonaws.com", {} }, + .{ "s3-object-lambda.us-gov-west-1.amazonaws.com", {} }, + .{ "s3-website.us-gov-west-1.amazonaws.com", {} }, + .{ "s3.dualstack.us-west-1.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.us-west-1.amazonaws.com", {} }, + .{ "s3-accesspoint-fips.dualstack.us-west-1.amazonaws.com", {} }, + .{ "s3-fips.dualstack.us-west-1.amazonaws.com", {} }, + .{ "s3-website.dualstack.us-west-1.amazonaws.com", {} }, + .{ "s3.us-west-1.amazonaws.com", {} }, + .{ "s3-accesspoint.us-west-1.amazonaws.com", {} }, + .{ "s3-accesspoint-fips.us-west-1.amazonaws.com", {} }, + .{ "s3-fips.us-west-1.amazonaws.com", {} }, + .{ "s3-object-lambda.us-west-1.amazonaws.com", {} }, + .{ "s3-website.us-west-1.amazonaws.com", {} }, + .{ "s3.dualstack.us-west-2.amazonaws.com", {} }, + .{ "s3-accesspoint.dualstack.us-west-2.amazonaws.com", {} }, + .{ "s3-accesspoint-fips.dualstack.us-west-2.amazonaws.com", {} }, + .{ "s3-fips.dualstack.us-west-2.amazonaws.com", {} }, + .{ "s3-website.dualstack.us-west-2.amazonaws.com", {} }, + .{ "s3.us-west-2.amazonaws.com", {} }, + .{ "s3-accesspoint.us-west-2.amazonaws.com", {} }, + .{ "s3-accesspoint-fips.us-west-2.amazonaws.com", {} }, + .{ "s3-deprecated.us-west-2.amazonaws.com", {} }, + .{ "s3-fips.us-west-2.amazonaws.com", {} }, + .{ "s3-object-lambda.us-west-2.amazonaws.com", {} }, + .{ "s3-website.us-west-2.amazonaws.com", {} }, + .{ "labeling.ap-northeast-1.sagemaker.aws", {} }, + .{ "labeling.ap-northeast-2.sagemaker.aws", {} }, + .{ "labeling.ap-south-1.sagemaker.aws", {} }, + .{ "labeling.ap-southeast-1.sagemaker.aws", {} }, + .{ "labeling.ap-southeast-2.sagemaker.aws", {} }, + .{ "labeling.ca-central-1.sagemaker.aws", {} }, + .{ "labeling.eu-central-1.sagemaker.aws", {} }, + .{ "labeling.eu-west-1.sagemaker.aws", {} }, + .{ "labeling.eu-west-2.sagemaker.aws", {} }, + .{ "labeling.us-east-1.sagemaker.aws", {} }, + .{ "labeling.us-east-2.sagemaker.aws", {} }, + .{ "labeling.us-west-2.sagemaker.aws", {} }, + .{ "notebook.af-south-1.sagemaker.aws", {} }, + .{ "notebook.ap-east-1.sagemaker.aws", {} }, + .{ "notebook.ap-northeast-1.sagemaker.aws", {} }, + .{ "notebook.ap-northeast-2.sagemaker.aws", {} }, + .{ "notebook.ap-northeast-3.sagemaker.aws", {} }, + .{ "notebook.ap-south-1.sagemaker.aws", {} }, + .{ "notebook.ap-south-2.sagemaker.aws", {} }, + .{ "notebook.ap-southeast-1.sagemaker.aws", {} }, + .{ "notebook.ap-southeast-2.sagemaker.aws", {} }, + .{ "notebook.ap-southeast-3.sagemaker.aws", {} }, + .{ "notebook.ap-southeast-4.sagemaker.aws", {} }, + .{ "notebook.ca-central-1.sagemaker.aws", {} }, + .{ "notebook-fips.ca-central-1.sagemaker.aws", {} }, + .{ "notebook.ca-west-1.sagemaker.aws", {} }, + .{ "notebook-fips.ca-west-1.sagemaker.aws", {} }, + .{ "notebook.eu-central-1.sagemaker.aws", {} }, + .{ "notebook.eu-central-2.sagemaker.aws", {} }, + .{ "notebook.eu-north-1.sagemaker.aws", {} }, + .{ "notebook.eu-south-1.sagemaker.aws", {} }, + .{ "notebook.eu-south-2.sagemaker.aws", {} }, + .{ "notebook.eu-west-1.sagemaker.aws", {} }, + .{ "notebook.eu-west-2.sagemaker.aws", {} }, + .{ "notebook.eu-west-3.sagemaker.aws", {} }, + .{ "notebook.il-central-1.sagemaker.aws", {} }, + .{ "notebook.me-central-1.sagemaker.aws", {} }, + .{ "notebook.me-south-1.sagemaker.aws", {} }, + .{ "notebook.sa-east-1.sagemaker.aws", {} }, + .{ "notebook.us-east-1.sagemaker.aws", {} }, + .{ "notebook-fips.us-east-1.sagemaker.aws", {} }, + .{ "notebook.us-east-2.sagemaker.aws", {} }, + .{ "notebook-fips.us-east-2.sagemaker.aws", {} }, + .{ "notebook.us-gov-east-1.sagemaker.aws", {} }, + .{ "notebook-fips.us-gov-east-1.sagemaker.aws", {} }, + .{ "notebook.us-gov-west-1.sagemaker.aws", {} }, + .{ "notebook-fips.us-gov-west-1.sagemaker.aws", {} }, + .{ "notebook.us-west-1.sagemaker.aws", {} }, + .{ "notebook-fips.us-west-1.sagemaker.aws", {} }, + .{ "notebook.us-west-2.sagemaker.aws", {} }, + .{ "notebook-fips.us-west-2.sagemaker.aws", {} }, + .{ "notebook.cn-north-1.sagemaker.com.cn", {} }, + .{ "notebook.cn-northwest-1.sagemaker.com.cn", {} }, + .{ "studio.af-south-1.sagemaker.aws", {} }, + .{ "studio.ap-east-1.sagemaker.aws", {} }, + .{ "studio.ap-northeast-1.sagemaker.aws", {} }, + .{ "studio.ap-northeast-2.sagemaker.aws", {} }, + .{ "studio.ap-northeast-3.sagemaker.aws", {} }, + .{ "studio.ap-south-1.sagemaker.aws", {} }, + .{ "studio.ap-southeast-1.sagemaker.aws", {} }, + .{ "studio.ap-southeast-2.sagemaker.aws", {} }, + .{ "studio.ap-southeast-3.sagemaker.aws", {} }, + .{ "studio.ca-central-1.sagemaker.aws", {} }, + .{ "studio.eu-central-1.sagemaker.aws", {} }, + .{ "studio.eu-central-2.sagemaker.aws", {} }, + .{ "studio.eu-north-1.sagemaker.aws", {} }, + .{ "studio.eu-south-1.sagemaker.aws", {} }, + .{ "studio.eu-south-2.sagemaker.aws", {} }, + .{ "studio.eu-west-1.sagemaker.aws", {} }, + .{ "studio.eu-west-2.sagemaker.aws", {} }, + .{ "studio.eu-west-3.sagemaker.aws", {} }, + .{ "studio.il-central-1.sagemaker.aws", {} }, + .{ "studio.me-central-1.sagemaker.aws", {} }, + .{ "studio.me-south-1.sagemaker.aws", {} }, + .{ "studio.sa-east-1.sagemaker.aws", {} }, + .{ "studio.us-east-1.sagemaker.aws", {} }, + .{ "studio.us-east-2.sagemaker.aws", {} }, + .{ "studio.us-gov-east-1.sagemaker.aws", {} }, + .{ "studio-fips.us-gov-east-1.sagemaker.aws", {} }, + .{ "studio.us-gov-west-1.sagemaker.aws", {} }, + .{ "studio-fips.us-gov-west-1.sagemaker.aws", {} }, + .{ "studio.us-west-1.sagemaker.aws", {} }, + .{ "studio.us-west-2.sagemaker.aws", {} }, + .{ "studio.cn-north-1.sagemaker.com.cn", {} }, + .{ "studio.cn-northwest-1.sagemaker.com.cn", {} }, + .{ "*.experiments.sagemaker.aws", {} }, + .{ "analytics-gateway.ap-northeast-1.amazonaws.com", {} }, + .{ "analytics-gateway.ap-northeast-2.amazonaws.com", {} }, + .{ "analytics-gateway.ap-south-1.amazonaws.com", {} }, + .{ "analytics-gateway.ap-southeast-1.amazonaws.com", {} }, + .{ "analytics-gateway.ap-southeast-2.amazonaws.com", {} }, + .{ "analytics-gateway.eu-central-1.amazonaws.com", {} }, + .{ "analytics-gateway.eu-west-1.amazonaws.com", {} }, + .{ "analytics-gateway.us-east-1.amazonaws.com", {} }, + .{ "analytics-gateway.us-east-2.amazonaws.com", {} }, + .{ "analytics-gateway.us-west-2.amazonaws.com", {} }, + .{ "amplifyapp.com", {} }, + .{ "*.awsapprunner.com", {} }, + .{ "webview-assets.aws-cloud9.af-south-1.amazonaws.com", {} }, + .{ "vfs.cloud9.af-south-1.amazonaws.com", {} }, + .{ "webview-assets.cloud9.af-south-1.amazonaws.com", {} }, + .{ "webview-assets.aws-cloud9.ap-east-1.amazonaws.com", {} }, + .{ "vfs.cloud9.ap-east-1.amazonaws.com", {} }, + .{ "webview-assets.cloud9.ap-east-1.amazonaws.com", {} }, + .{ "webview-assets.aws-cloud9.ap-northeast-1.amazonaws.com", {} }, + .{ "vfs.cloud9.ap-northeast-1.amazonaws.com", {} }, + .{ "webview-assets.cloud9.ap-northeast-1.amazonaws.com", {} }, + .{ "webview-assets.aws-cloud9.ap-northeast-2.amazonaws.com", {} }, + .{ "vfs.cloud9.ap-northeast-2.amazonaws.com", {} }, + .{ "webview-assets.cloud9.ap-northeast-2.amazonaws.com", {} }, + .{ "webview-assets.aws-cloud9.ap-northeast-3.amazonaws.com", {} }, + .{ "vfs.cloud9.ap-northeast-3.amazonaws.com", {} }, + .{ "webview-assets.cloud9.ap-northeast-3.amazonaws.com", {} }, + .{ "webview-assets.aws-cloud9.ap-south-1.amazonaws.com", {} }, + .{ "vfs.cloud9.ap-south-1.amazonaws.com", {} }, + .{ "webview-assets.cloud9.ap-south-1.amazonaws.com", {} }, + .{ "webview-assets.aws-cloud9.ap-southeast-1.amazonaws.com", {} }, + .{ "vfs.cloud9.ap-southeast-1.amazonaws.com", {} }, + .{ "webview-assets.cloud9.ap-southeast-1.amazonaws.com", {} }, + .{ "webview-assets.aws-cloud9.ap-southeast-2.amazonaws.com", {} }, + .{ "vfs.cloud9.ap-southeast-2.amazonaws.com", {} }, + .{ "webview-assets.cloud9.ap-southeast-2.amazonaws.com", {} }, + .{ "webview-assets.aws-cloud9.ca-central-1.amazonaws.com", {} }, + .{ "vfs.cloud9.ca-central-1.amazonaws.com", {} }, + .{ "webview-assets.cloud9.ca-central-1.amazonaws.com", {} }, + .{ "webview-assets.aws-cloud9.eu-central-1.amazonaws.com", {} }, + .{ "vfs.cloud9.eu-central-1.amazonaws.com", {} }, + .{ "webview-assets.cloud9.eu-central-1.amazonaws.com", {} }, + .{ "webview-assets.aws-cloud9.eu-north-1.amazonaws.com", {} }, + .{ "vfs.cloud9.eu-north-1.amazonaws.com", {} }, + .{ "webview-assets.cloud9.eu-north-1.amazonaws.com", {} }, + .{ "webview-assets.aws-cloud9.eu-south-1.amazonaws.com", {} }, + .{ "vfs.cloud9.eu-south-1.amazonaws.com", {} }, + .{ "webview-assets.cloud9.eu-south-1.amazonaws.com", {} }, + .{ "webview-assets.aws-cloud9.eu-west-1.amazonaws.com", {} }, + .{ "vfs.cloud9.eu-west-1.amazonaws.com", {} }, + .{ "webview-assets.cloud9.eu-west-1.amazonaws.com", {} }, + .{ "webview-assets.aws-cloud9.eu-west-2.amazonaws.com", {} }, + .{ "vfs.cloud9.eu-west-2.amazonaws.com", {} }, + .{ "webview-assets.cloud9.eu-west-2.amazonaws.com", {} }, + .{ "webview-assets.aws-cloud9.eu-west-3.amazonaws.com", {} }, + .{ "vfs.cloud9.eu-west-3.amazonaws.com", {} }, + .{ "webview-assets.cloud9.eu-west-3.amazonaws.com", {} }, + .{ "webview-assets.aws-cloud9.il-central-1.amazonaws.com", {} }, + .{ "vfs.cloud9.il-central-1.amazonaws.com", {} }, + .{ "webview-assets.aws-cloud9.me-south-1.amazonaws.com", {} }, + .{ "vfs.cloud9.me-south-1.amazonaws.com", {} }, + .{ "webview-assets.cloud9.me-south-1.amazonaws.com", {} }, + .{ "webview-assets.aws-cloud9.sa-east-1.amazonaws.com", {} }, + .{ "vfs.cloud9.sa-east-1.amazonaws.com", {} }, + .{ "webview-assets.cloud9.sa-east-1.amazonaws.com", {} }, + .{ "webview-assets.aws-cloud9.us-east-1.amazonaws.com", {} }, + .{ "vfs.cloud9.us-east-1.amazonaws.com", {} }, + .{ "webview-assets.cloud9.us-east-1.amazonaws.com", {} }, + .{ "webview-assets.aws-cloud9.us-east-2.amazonaws.com", {} }, + .{ "vfs.cloud9.us-east-2.amazonaws.com", {} }, + .{ "webview-assets.cloud9.us-east-2.amazonaws.com", {} }, + .{ "webview-assets.aws-cloud9.us-west-1.amazonaws.com", {} }, + .{ "vfs.cloud9.us-west-1.amazonaws.com", {} }, + .{ "webview-assets.cloud9.us-west-1.amazonaws.com", {} }, + .{ "webview-assets.aws-cloud9.us-west-2.amazonaws.com", {} }, + .{ "vfs.cloud9.us-west-2.amazonaws.com", {} }, + .{ "webview-assets.cloud9.us-west-2.amazonaws.com", {} }, + .{ "awsapps.com", {} }, + .{ "cn-north-1.eb.amazonaws.com.cn", {} }, + .{ "cn-northwest-1.eb.amazonaws.com.cn", {} }, + .{ "elasticbeanstalk.com", {} }, + .{ "af-south-1.elasticbeanstalk.com", {} }, + .{ "ap-east-1.elasticbeanstalk.com", {} }, + .{ "ap-northeast-1.elasticbeanstalk.com", {} }, + .{ "ap-northeast-2.elasticbeanstalk.com", {} }, + .{ "ap-northeast-3.elasticbeanstalk.com", {} }, + .{ "ap-south-1.elasticbeanstalk.com", {} }, + .{ "ap-southeast-1.elasticbeanstalk.com", {} }, + .{ "ap-southeast-2.elasticbeanstalk.com", {} }, + .{ "ap-southeast-3.elasticbeanstalk.com", {} }, + .{ "ca-central-1.elasticbeanstalk.com", {} }, + .{ "eu-central-1.elasticbeanstalk.com", {} }, + .{ "eu-north-1.elasticbeanstalk.com", {} }, + .{ "eu-south-1.elasticbeanstalk.com", {} }, + .{ "eu-west-1.elasticbeanstalk.com", {} }, + .{ "eu-west-2.elasticbeanstalk.com", {} }, + .{ "eu-west-3.elasticbeanstalk.com", {} }, + .{ "il-central-1.elasticbeanstalk.com", {} }, + .{ "me-south-1.elasticbeanstalk.com", {} }, + .{ "sa-east-1.elasticbeanstalk.com", {} }, + .{ "us-east-1.elasticbeanstalk.com", {} }, + .{ "us-east-2.elasticbeanstalk.com", {} }, + .{ "us-gov-east-1.elasticbeanstalk.com", {} }, + .{ "us-gov-west-1.elasticbeanstalk.com", {} }, + .{ "us-west-1.elasticbeanstalk.com", {} }, + .{ "us-west-2.elasticbeanstalk.com", {} }, + .{ "*.elb.amazonaws.com.cn", {} }, + .{ "*.elb.amazonaws.com", {} }, + .{ "awsglobalaccelerator.com", {} }, + .{ "*.private.repost.aws", {} }, + .{ "transfer-webapp.ap-northeast-1.on.aws", {} }, + .{ "transfer-webapp.ap-southeast-1.on.aws", {} }, + .{ "transfer-webapp.ap-southeast-2.on.aws", {} }, + .{ "transfer-webapp.eu-central-1.on.aws", {} }, + .{ "transfer-webapp.eu-north-1.on.aws", {} }, + .{ "transfer-webapp.eu-west-1.on.aws", {} }, + .{ "transfer-webapp.us-east-1.on.aws", {} }, + .{ "transfer-webapp.us-east-2.on.aws", {} }, + .{ "transfer-webapp.us-west-2.on.aws", {} }, + .{ "eero.online", {} }, + .{ "eero-stage.online", {} }, + .{ "apigee.io", {} }, + .{ "panel.dev", {} }, + .{ "siiites.com", {} }, + .{ "appspacehosted.com", {} }, + .{ "appspaceusercontent.com", {} }, + .{ "appudo.net", {} }, + .{ "on-aptible.com", {} }, + .{ "f5.si", {} }, + .{ "arvanedge.ir", {} }, + .{ "user.aseinet.ne.jp", {} }, + .{ "gv.vc", {} }, + .{ "d.gv.vc", {} }, + .{ "user.party.eus", {} }, + .{ "pimienta.org", {} }, + .{ "poivron.org", {} }, + .{ "potager.org", {} }, + .{ "sweetpepper.org", {} }, + .{ "myasustor.com", {} }, + .{ "cdn.prod.atlassian-dev.net", {} }, + .{ "translated.page", {} }, + .{ "myfritz.link", {} }, + .{ "myfritz.net", {} }, + .{ "onavstack.net", {} }, + .{ "*.awdev.ca", {} }, + .{ "*.advisor.ws", {} }, + .{ "ecommerce-shop.pl", {} }, + .{ "b-data.io", {} }, + .{ "balena-devices.com", {} }, + .{ "base.ec", {} }, + .{ "official.ec", {} }, + .{ "buyshop.jp", {} }, + .{ "fashionstore.jp", {} }, + .{ "handcrafted.jp", {} }, + .{ "kawaiishop.jp", {} }, + .{ "supersale.jp", {} }, + .{ "theshop.jp", {} }, + .{ "shopselect.net", {} }, + .{ "base.shop", {} }, + .{ "beagleboard.io", {} }, + .{ "*.beget.app", {} }, + .{ "pages.gay", {} }, + .{ "bnr.la", {} }, + .{ "bitbucket.io", {} }, + .{ "blackbaudcdn.net", {} }, + .{ "of.je", {} }, + .{ "square.site", {} }, + .{ "bluebite.io", {} }, + .{ "boomla.net", {} }, + .{ "boutir.com", {} }, + .{ "boxfuse.io", {} }, + .{ "square7.ch", {} }, + .{ "bplaced.com", {} }, + .{ "bplaced.de", {} }, + .{ "square7.de", {} }, + .{ "bplaced.net", {} }, + .{ "square7.net", {} }, + .{ "brave.app", {} }, + .{ "*.s.brave.app", {} }, + .{ "brave.io", {} }, + .{ "*.s.brave.io", {} }, + .{ "shop.brendly.hr", {} }, + .{ "shop.brendly.rs", {} }, + .{ "browsersafetymark.io", {} }, + .{ "radio.am", {} }, + .{ "radio.fm", {} }, + .{ "cdn.bubble.io", {} }, + .{ "bubbleapps.io", {} }, + .{ "uk0.bigv.io", {} }, + .{ "dh.bytemark.co.uk", {} }, + .{ "vm.bytemark.co.uk", {} }, + .{ "cafjs.com", {} }, + .{ "canva-apps.cn", {} }, + .{ "*.my.canvasite.cn", {} }, + .{ "canva-apps.com", {} }, + .{ "*.my.canva.site", {} }, + .{ "drr.ac", {} }, + .{ "uwu.ai", {} }, + .{ "carrd.co", {} }, + .{ "crd.co", {} }, + .{ "ju.mp", {} }, + .{ "api.gov.uk", {} }, + .{ "cdn77-storage.com", {} }, + .{ "rsc.contentproxy9.cz", {} }, + .{ "r.cdn77.net", {} }, + .{ "cdn77-ssl.net", {} }, + .{ "c.cdn77.org", {} }, + .{ "rsc.cdn77.org", {} }, + .{ "ssl.origin.cdn77-secure.org", {} }, + .{ "za.bz", {} }, + .{ "br.com", {} }, + .{ "cn.com", {} }, + .{ "de.com", {} }, + .{ "eu.com", {} }, + .{ "jpn.com", {} }, + .{ "mex.com", {} }, + .{ "ru.com", {} }, + .{ "sa.com", {} }, + .{ "uk.com", {} }, + .{ "us.com", {} }, + .{ "za.com", {} }, + .{ "com.de", {} }, + .{ "gb.net", {} }, + .{ "hu.net", {} }, + .{ "jp.net", {} }, + .{ "se.net", {} }, + .{ "uk.net", {} }, + .{ "ae.org", {} }, + .{ "com.se", {} }, + .{ "cx.ua", {} }, + .{ "discourse.group", {} }, + .{ "discourse.team", {} }, + .{ "clerk.app", {} }, + .{ "clerkstage.app", {} }, + .{ "*.lcl.dev", {} }, + .{ "*.lclstage.dev", {} }, + .{ "*.stg.dev", {} }, + .{ "*.stgstage.dev", {} }, + .{ "cleverapps.cc", {} }, + .{ "*.services.clever-cloud.com", {} }, + .{ "cleverapps.io", {} }, + .{ "cleverapps.tech", {} }, + .{ "clickrising.net", {} }, + .{ "cloudns.asia", {} }, + .{ "cloudns.be", {} }, + .{ "cloud-ip.biz", {} }, + .{ "cloudns.biz", {} }, + .{ "cloudns.cc", {} }, + .{ "cloudns.ch", {} }, + .{ "cloudns.cl", {} }, + .{ "cloudns.club", {} }, + .{ "dnsabr.com", {} }, + .{ "ip-ddns.com", {} }, + .{ "cloudns.cx", {} }, + .{ "cloudns.eu", {} }, + .{ "cloudns.in", {} }, + .{ "cloudns.info", {} }, + .{ "ddns-ip.net", {} }, + .{ "dns-cloud.net", {} }, + .{ "dns-dynamic.net", {} }, + .{ "cloudns.nz", {} }, + .{ "cloudns.org", {} }, + .{ "ip-dynamic.org", {} }, + .{ "cloudns.ph", {} }, + .{ "cloudns.pro", {} }, + .{ "cloudns.pw", {} }, + .{ "cloudns.us", {} }, + .{ "c66.me", {} }, + .{ "cloud66.ws", {} }, + .{ "cloud66.zone", {} }, + .{ "jdevcloud.com", {} }, + .{ "wpdevcloud.com", {} }, + .{ "cloudaccess.host", {} }, + .{ "freesite.host", {} }, + .{ "cloudaccess.net", {} }, + .{ "cloudbeesusercontent.io", {} }, + .{ "*.cloudera.site", {} }, + .{ "cf-ipfs.com", {} }, + .{ "cloudflare-ipfs.com", {} }, + .{ "trycloudflare.com", {} }, + .{ "pages.dev", {} }, + .{ "r2.dev", {} }, + .{ "workers.dev", {} }, + .{ "cloudflare.net", {} }, + .{ "cdn.cloudflare.net", {} }, + .{ "cdn.cloudflareanycast.net", {} }, + .{ "cdn.cloudflarecn.net", {} }, + .{ "cdn.cloudflareglobal.net", {} }, + .{ "cust.cloudscale.ch", {} }, + .{ "objects.lpg.cloudscale.ch", {} }, + .{ "objects.rma.cloudscale.ch", {} }, + .{ "wnext.app", {} }, + .{ "cnpy.gdn", {} }, + .{ "*.otap.co", {} }, + .{ "co.ca", {} }, + .{ "co.com", {} }, + .{ "codeberg.page", {} }, + .{ "csb.app", {} }, + .{ "preview.csb.app", {} }, + .{ "co.nl", {} }, + .{ "co.no", {} }, + .{ "webhosting.be", {} }, + .{ "hosting-cluster.nl", {} }, + .{ "ctfcloud.net", {} }, + .{ "convex.site", {} }, + .{ "ac.ru", {} }, + .{ "edu.ru", {} }, + .{ "gov.ru", {} }, + .{ "int.ru", {} }, + .{ "mil.ru", {} }, + .{ "dyn.cosidns.de", {} }, + .{ "dnsupdater.de", {} }, + .{ "dynamisches-dns.de", {} }, + .{ "internet-dns.de", {} }, + .{ "l-o-g-i-n.de", {} }, + .{ "dynamic-dns.info", {} }, + .{ "feste-ip.net", {} }, + .{ "knx-server.net", {} }, + .{ "static-access.net", {} }, + .{ "craft.me", {} }, + .{ "realm.cz", {} }, + .{ "on.crisp.email", {} }, + .{ "*.cryptonomic.net", {} }, + .{ "cfolks.pl", {} }, + .{ "cyon.link", {} }, + .{ "cyon.site", {} }, + .{ "biz.dk", {} }, + .{ "co.dk", {} }, + .{ "firm.dk", {} }, + .{ "reg.dk", {} }, + .{ "store.dk", {} }, + .{ "dyndns.dappnode.io", {} }, + .{ "builtwithdark.com", {} }, + .{ "darklang.io", {} }, + .{ "demo.datadetect.com", {} }, + .{ "instance.datadetect.com", {} }, + .{ "edgestack.me", {} }, + .{ "dattolocal.com", {} }, + .{ "dattorelay.com", {} }, + .{ "dattoweb.com", {} }, + .{ "mydatto.com", {} }, + .{ "dattolocal.net", {} }, + .{ "mydatto.net", {} }, + .{ "ddnss.de", {} }, + .{ "dyn.ddnss.de", {} }, + .{ "dyndns.ddnss.de", {} }, + .{ "dyn-ip24.de", {} }, + .{ "dyndns1.de", {} }, + .{ "home-webserver.de", {} }, + .{ "dyn.home-webserver.de", {} }, + .{ "myhome-server.de", {} }, + .{ "ddnss.org", {} }, + .{ "debian.net", {} }, + .{ "definima.io", {} }, + .{ "definima.net", {} }, + .{ "deno.dev", {} }, + .{ "deno-staging.dev", {} }, + .{ "dedyn.io", {} }, + .{ "deta.app", {} }, + .{ "deta.dev", {} }, + .{ "dfirma.pl", {} }, + .{ "dkonto.pl", {} }, + .{ "you2.pl", {} }, + .{ "ondigitalocean.app", {} }, + .{ "*.digitaloceanspaces.com", {} }, + .{ "us.kg", {} }, + .{ "discordsays.com", {} }, + .{ "discordsez.com", {} }, + .{ "jozi.biz", {} }, + .{ "dnshome.de", {} }, + .{ "online.th", {} }, + .{ "shop.th", {} }, + .{ "drayddns.com", {} }, + .{ "shoparena.pl", {} }, + .{ "dreamhosters.com", {} }, + .{ "durumis.com", {} }, + .{ "mydrobo.com", {} }, + .{ "duckdns.org", {} }, + .{ "dy.fi", {} }, + .{ "tunk.org", {} }, + .{ "dyndns.biz", {} }, + .{ "for-better.biz", {} }, + .{ "for-more.biz", {} }, + .{ "for-some.biz", {} }, + .{ "for-the.biz", {} }, + .{ "selfip.biz", {} }, + .{ "webhop.biz", {} }, + .{ "ftpaccess.cc", {} }, + .{ "game-server.cc", {} }, + .{ "myphotos.cc", {} }, + .{ "scrapping.cc", {} }, + .{ "blogdns.com", {} }, + .{ "cechire.com", {} }, + .{ "dnsalias.com", {} }, + .{ "dnsdojo.com", {} }, + .{ "doesntexist.com", {} }, + .{ "dontexist.com", {} }, + .{ "doomdns.com", {} }, + .{ "dyn-o-saur.com", {} }, + .{ "dynalias.com", {} }, + .{ "dyndns-at-home.com", {} }, + .{ "dyndns-at-work.com", {} }, + .{ "dyndns-blog.com", {} }, + .{ "dyndns-free.com", {} }, + .{ "dyndns-home.com", {} }, + .{ "dyndns-ip.com", {} }, + .{ "dyndns-mail.com", {} }, + .{ "dyndns-office.com", {} }, + .{ "dyndns-pics.com", {} }, + .{ "dyndns-remote.com", {} }, + .{ "dyndns-server.com", {} }, + .{ "dyndns-web.com", {} }, + .{ "dyndns-wiki.com", {} }, + .{ "dyndns-work.com", {} }, + .{ "est-a-la-maison.com", {} }, + .{ "est-a-la-masion.com", {} }, + .{ "est-le-patron.com", {} }, + .{ "est-mon-blogueur.com", {} }, + .{ "from-ak.com", {} }, + .{ "from-al.com", {} }, + .{ "from-ar.com", {} }, + .{ "from-ca.com", {} }, + .{ "from-ct.com", {} }, + .{ "from-dc.com", {} }, + .{ "from-de.com", {} }, + .{ "from-fl.com", {} }, + .{ "from-ga.com", {} }, + .{ "from-hi.com", {} }, + .{ "from-ia.com", {} }, + .{ "from-id.com", {} }, + .{ "from-il.com", {} }, + .{ "from-in.com", {} }, + .{ "from-ks.com", {} }, + .{ "from-ky.com", {} }, + .{ "from-ma.com", {} }, + .{ "from-md.com", {} }, + .{ "from-mi.com", {} }, + .{ "from-mn.com", {} }, + .{ "from-mo.com", {} }, + .{ "from-ms.com", {} }, + .{ "from-mt.com", {} }, + .{ "from-nc.com", {} }, + .{ "from-nd.com", {} }, + .{ "from-ne.com", {} }, + .{ "from-nh.com", {} }, + .{ "from-nj.com", {} }, + .{ "from-nm.com", {} }, + .{ "from-nv.com", {} }, + .{ "from-oh.com", {} }, + .{ "from-ok.com", {} }, + .{ "from-or.com", {} }, + .{ "from-pa.com", {} }, + .{ "from-pr.com", {} }, + .{ "from-ri.com", {} }, + .{ "from-sc.com", {} }, + .{ "from-sd.com", {} }, + .{ "from-tn.com", {} }, + .{ "from-tx.com", {} }, + .{ "from-ut.com", {} }, + .{ "from-va.com", {} }, + .{ "from-vt.com", {} }, + .{ "from-wa.com", {} }, + .{ "from-wi.com", {} }, + .{ "from-wv.com", {} }, + .{ "from-wy.com", {} }, + .{ "getmyip.com", {} }, + .{ "gotdns.com", {} }, + .{ "hobby-site.com", {} }, + .{ "homelinux.com", {} }, + .{ "homeunix.com", {} }, + .{ "iamallama.com", {} }, + .{ "is-a-anarchist.com", {} }, + .{ "is-a-blogger.com", {} }, + .{ "is-a-bookkeeper.com", {} }, + .{ "is-a-bulls-fan.com", {} }, + .{ "is-a-caterer.com", {} }, + .{ "is-a-chef.com", {} }, + .{ "is-a-conservative.com", {} }, + .{ "is-a-cpa.com", {} }, + .{ "is-a-cubicle-slave.com", {} }, + .{ "is-a-democrat.com", {} }, + .{ "is-a-designer.com", {} }, + .{ "is-a-doctor.com", {} }, + .{ "is-a-financialadvisor.com", {} }, + .{ "is-a-geek.com", {} }, + .{ "is-a-green.com", {} }, + .{ "is-a-guru.com", {} }, + .{ "is-a-hard-worker.com", {} }, + .{ "is-a-hunter.com", {} }, + .{ "is-a-landscaper.com", {} }, + .{ "is-a-lawyer.com", {} }, + .{ "is-a-liberal.com", {} }, + .{ "is-a-libertarian.com", {} }, + .{ "is-a-llama.com", {} }, + .{ "is-a-musician.com", {} }, + .{ "is-a-nascarfan.com", {} }, + .{ "is-a-nurse.com", {} }, + .{ "is-a-painter.com", {} }, + .{ "is-a-personaltrainer.com", {} }, + .{ "is-a-photographer.com", {} }, + .{ "is-a-player.com", {} }, + .{ "is-a-republican.com", {} }, + .{ "is-a-rockstar.com", {} }, + .{ "is-a-socialist.com", {} }, + .{ "is-a-student.com", {} }, + .{ "is-a-teacher.com", {} }, + .{ "is-a-techie.com", {} }, + .{ "is-a-therapist.com", {} }, + .{ "is-an-accountant.com", {} }, + .{ "is-an-actor.com", {} }, + .{ "is-an-actress.com", {} }, + .{ "is-an-anarchist.com", {} }, + .{ "is-an-artist.com", {} }, + .{ "is-an-engineer.com", {} }, + .{ "is-an-entertainer.com", {} }, + .{ "is-certified.com", {} }, + .{ "is-gone.com", {} }, + .{ "is-into-anime.com", {} }, + .{ "is-into-cars.com", {} }, + .{ "is-into-cartoons.com", {} }, + .{ "is-into-games.com", {} }, + .{ "is-leet.com", {} }, + .{ "is-not-certified.com", {} }, + .{ "is-slick.com", {} }, + .{ "is-uberleet.com", {} }, + .{ "is-with-theband.com", {} }, + .{ "isa-geek.com", {} }, + .{ "isa-hockeynut.com", {} }, + .{ "issmarterthanyou.com", {} }, + .{ "likes-pie.com", {} }, + .{ "likescandy.com", {} }, + .{ "neat-url.com", {} }, + .{ "saves-the-whales.com", {} }, + .{ "selfip.com", {} }, + .{ "sells-for-less.com", {} }, + .{ "sells-for-u.com", {} }, + .{ "servebbs.com", {} }, + .{ "simple-url.com", {} }, + .{ "space-to-rent.com", {} }, + .{ "teaches-yoga.com", {} }, + .{ "writesthisblog.com", {} }, + .{ "ath.cx", {} }, + .{ "fuettertdasnetz.de", {} }, + .{ "isteingeek.de", {} }, + .{ "istmein.de", {} }, + .{ "lebtimnetz.de", {} }, + .{ "leitungsen.de", {} }, + .{ "traeumtgerade.de", {} }, + .{ "barrel-of-knowledge.info", {} }, + .{ "barrell-of-knowledge.info", {} }, + .{ "dyndns.info", {} }, + .{ "for-our.info", {} }, + .{ "groks-the.info", {} }, + .{ "groks-this.info", {} }, + .{ "here-for-more.info", {} }, + .{ "knowsitall.info", {} }, + .{ "selfip.info", {} }, + .{ "webhop.info", {} }, + .{ "forgot.her.name", {} }, + .{ "forgot.his.name", {} }, + .{ "at-band-camp.net", {} }, + .{ "blogdns.net", {} }, + .{ "broke-it.net", {} }, + .{ "buyshouses.net", {} }, + .{ "dnsalias.net", {} }, + .{ "dnsdojo.net", {} }, + .{ "does-it.net", {} }, + .{ "dontexist.net", {} }, + .{ "dynalias.net", {} }, + .{ "dynathome.net", {} }, + .{ "endofinternet.net", {} }, + .{ "from-az.net", {} }, + .{ "from-co.net", {} }, + .{ "from-la.net", {} }, + .{ "from-ny.net", {} }, + .{ "gets-it.net", {} }, + .{ "ham-radio-op.net", {} }, + .{ "homeftp.net", {} }, + .{ "homeip.net", {} }, + .{ "homelinux.net", {} }, + .{ "homeunix.net", {} }, + .{ "in-the-band.net", {} }, + .{ "is-a-chef.net", {} }, + .{ "is-a-geek.net", {} }, + .{ "isa-geek.net", {} }, + .{ "kicks-ass.net", {} }, + .{ "office-on-the.net", {} }, + .{ "podzone.net", {} }, + .{ "scrapper-site.net", {} }, + .{ "selfip.net", {} }, + .{ "sells-it.net", {} }, + .{ "servebbs.net", {} }, + .{ "serveftp.net", {} }, + .{ "thruhere.net", {} }, + .{ "webhop.net", {} }, + .{ "merseine.nu", {} }, + .{ "mine.nu", {} }, + .{ "shacknet.nu", {} }, + .{ "blogdns.org", {} }, + .{ "blogsite.org", {} }, + .{ "boldlygoingnowhere.org", {} }, + .{ "dnsalias.org", {} }, + .{ "dnsdojo.org", {} }, + .{ "doesntexist.org", {} }, + .{ "dontexist.org", {} }, + .{ "doomdns.org", {} }, + .{ "dvrdns.org", {} }, + .{ "dynalias.org", {} }, + .{ "dyndns.org", {} }, + .{ "go.dyndns.org", {} }, + .{ "home.dyndns.org", {} }, + .{ "endofinternet.org", {} }, + .{ "endoftheinternet.org", {} }, + .{ "from-me.org", {} }, + .{ "game-host.org", {} }, + .{ "gotdns.org", {} }, + .{ "hobby-site.org", {} }, + .{ "homedns.org", {} }, + .{ "homeftp.org", {} }, + .{ "homelinux.org", {} }, + .{ "homeunix.org", {} }, + .{ "is-a-bruinsfan.org", {} }, + .{ "is-a-candidate.org", {} }, + .{ "is-a-celticsfan.org", {} }, + .{ "is-a-chef.org", {} }, + .{ "is-a-geek.org", {} }, + .{ "is-a-knight.org", {} }, + .{ "is-a-linux-user.org", {} }, + .{ "is-a-patsfan.org", {} }, + .{ "is-a-soxfan.org", {} }, + .{ "is-found.org", {} }, + .{ "is-lost.org", {} }, + .{ "is-saved.org", {} }, + .{ "is-very-bad.org", {} }, + .{ "is-very-evil.org", {} }, + .{ "is-very-good.org", {} }, + .{ "is-very-nice.org", {} }, + .{ "is-very-sweet.org", {} }, + .{ "isa-geek.org", {} }, + .{ "kicks-ass.org", {} }, + .{ "misconfused.org", {} }, + .{ "podzone.org", {} }, + .{ "readmyblog.org", {} }, + .{ "selfip.org", {} }, + .{ "sellsyourhome.org", {} }, + .{ "servebbs.org", {} }, + .{ "serveftp.org", {} }, + .{ "servegame.org", {} }, + .{ "stuff-4-sale.org", {} }, + .{ "webhop.org", {} }, + .{ "better-than.tv", {} }, + .{ "dyndns.tv", {} }, + .{ "on-the-web.tv", {} }, + .{ "worse-than.tv", {} }, + .{ "is-by.us", {} }, + .{ "land-4-sale.us", {} }, + .{ "stuff-4-sale.us", {} }, + .{ "dyndns.ws", {} }, + .{ "mypets.ws", {} }, + .{ "ddnsfree.com", {} }, + .{ "ddnsgeek.com", {} }, + .{ "giize.com", {} }, + .{ "gleeze.com", {} }, + .{ "kozow.com", {} }, + .{ "loseyourip.com", {} }, + .{ "ooguy.com", {} }, + .{ "theworkpc.com", {} }, + .{ "casacam.net", {} }, + .{ "dynu.net", {} }, + .{ "accesscam.org", {} }, + .{ "camdvr.org", {} }, + .{ "freeddns.org", {} }, + .{ "mywire.org", {} }, + .{ "webredirect.org", {} }, + .{ "myddns.rocks", {} }, + .{ "dynv6.net", {} }, + .{ "e4.cz", {} }, + .{ "easypanel.app", {} }, + .{ "easypanel.host", {} }, + .{ "*.ewp.live", {} }, + .{ "twmail.cc", {} }, + .{ "twmail.net", {} }, + .{ "twmail.org", {} }, + .{ "mymailer.com.tw", {} }, + .{ "url.tw", {} }, + .{ "at.emf.camp", {} }, + .{ "rt.ht", {} }, + .{ "elementor.cloud", {} }, + .{ "elementor.cool", {} }, + .{ "en-root.fr", {} }, + .{ "mytuleap.com", {} }, + .{ "tuleap-partners.com", {} }, + .{ "encr.app", {} }, + .{ "encoreapi.com", {} }, + .{ "eu.encoway.cloud", {} }, + .{ "eu.org", {} }, + .{ "al.eu.org", {} }, + .{ "asso.eu.org", {} }, + .{ "at.eu.org", {} }, + .{ "au.eu.org", {} }, + .{ "be.eu.org", {} }, + .{ "bg.eu.org", {} }, + .{ "ca.eu.org", {} }, + .{ "cd.eu.org", {} }, + .{ "ch.eu.org", {} }, + .{ "cn.eu.org", {} }, + .{ "cy.eu.org", {} }, + .{ "cz.eu.org", {} }, + .{ "de.eu.org", {} }, + .{ "dk.eu.org", {} }, + .{ "edu.eu.org", {} }, + .{ "ee.eu.org", {} }, + .{ "es.eu.org", {} }, + .{ "fi.eu.org", {} }, + .{ "fr.eu.org", {} }, + .{ "gr.eu.org", {} }, + .{ "hr.eu.org", {} }, + .{ "hu.eu.org", {} }, + .{ "ie.eu.org", {} }, + .{ "il.eu.org", {} }, + .{ "in.eu.org", {} }, + .{ "int.eu.org", {} }, + .{ "is.eu.org", {} }, + .{ "it.eu.org", {} }, + .{ "jp.eu.org", {} }, + .{ "kr.eu.org", {} }, + .{ "lt.eu.org", {} }, + .{ "lu.eu.org", {} }, + .{ "lv.eu.org", {} }, + .{ "me.eu.org", {} }, + .{ "mk.eu.org", {} }, + .{ "mt.eu.org", {} }, + .{ "my.eu.org", {} }, + .{ "net.eu.org", {} }, + .{ "ng.eu.org", {} }, + .{ "nl.eu.org", {} }, + .{ "no.eu.org", {} }, + .{ "nz.eu.org", {} }, + .{ "pl.eu.org", {} }, + .{ "pt.eu.org", {} }, + .{ "ro.eu.org", {} }, + .{ "ru.eu.org", {} }, + .{ "se.eu.org", {} }, + .{ "si.eu.org", {} }, + .{ "sk.eu.org", {} }, + .{ "tr.eu.org", {} }, + .{ "uk.eu.org", {} }, + .{ "us.eu.org", {} }, + .{ "eurodir.ru", {} }, + .{ "eu-1.evennode.com", {} }, + .{ "eu-2.evennode.com", {} }, + .{ "eu-3.evennode.com", {} }, + .{ "eu-4.evennode.com", {} }, + .{ "us-1.evennode.com", {} }, + .{ "us-2.evennode.com", {} }, + .{ "us-3.evennode.com", {} }, + .{ "us-4.evennode.com", {} }, + .{ "relay.evervault.app", {} }, + .{ "relay.evervault.dev", {} }, + .{ "expo.app", {} }, + .{ "staging.expo.app", {} }, + .{ "onfabrica.com", {} }, + .{ "ru.net", {} }, + .{ "adygeya.ru", {} }, + .{ "bashkiria.ru", {} }, + .{ "bir.ru", {} }, + .{ "cbg.ru", {} }, + .{ "com.ru", {} }, + .{ "dagestan.ru", {} }, + .{ "grozny.ru", {} }, + .{ "kalmykia.ru", {} }, + .{ "kustanai.ru", {} }, + .{ "marine.ru", {} }, + .{ "mordovia.ru", {} }, + .{ "msk.ru", {} }, + .{ "mytis.ru", {} }, + .{ "nalchik.ru", {} }, + .{ "nov.ru", {} }, + .{ "pyatigorsk.ru", {} }, + .{ "spb.ru", {} }, + .{ "vladikavkaz.ru", {} }, + .{ "vladimir.ru", {} }, + .{ "abkhazia.su", {} }, + .{ "adygeya.su", {} }, + .{ "aktyubinsk.su", {} }, + .{ "arkhangelsk.su", {} }, + .{ "armenia.su", {} }, + .{ "ashgabad.su", {} }, + .{ "azerbaijan.su", {} }, + .{ "balashov.su", {} }, + .{ "bashkiria.su", {} }, + .{ "bryansk.su", {} }, + .{ "bukhara.su", {} }, + .{ "chimkent.su", {} }, + .{ "dagestan.su", {} }, + .{ "east-kazakhstan.su", {} }, + .{ "exnet.su", {} }, + .{ "georgia.su", {} }, + .{ "grozny.su", {} }, + .{ "ivanovo.su", {} }, + .{ "jambyl.su", {} }, + .{ "kalmykia.su", {} }, + .{ "kaluga.su", {} }, + .{ "karacol.su", {} }, + .{ "karaganda.su", {} }, + .{ "karelia.su", {} }, + .{ "khakassia.su", {} }, + .{ "krasnodar.su", {} }, + .{ "kurgan.su", {} }, + .{ "kustanai.su", {} }, + .{ "lenug.su", {} }, + .{ "mangyshlak.su", {} }, + .{ "mordovia.su", {} }, + .{ "msk.su", {} }, + .{ "murmansk.su", {} }, + .{ "nalchik.su", {} }, + .{ "navoi.su", {} }, + .{ "north-kazakhstan.su", {} }, + .{ "nov.su", {} }, + .{ "obninsk.su", {} }, + .{ "penza.su", {} }, + .{ "pokrovsk.su", {} }, + .{ "sochi.su", {} }, + .{ "spb.su", {} }, + .{ "tashkent.su", {} }, + .{ "termez.su", {} }, + .{ "togliatti.su", {} }, + .{ "troitsk.su", {} }, + .{ "tselinograd.su", {} }, + .{ "tula.su", {} }, + .{ "tuva.su", {} }, + .{ "vladikavkaz.su", {} }, + .{ "vladimir.su", {} }, + .{ "vologda.su", {} }, + .{ "channelsdvr.net", {} }, + .{ "u.channelsdvr.net", {} }, + .{ "edgecompute.app", {} }, + .{ "fastly-edge.com", {} }, + .{ "fastly-terrarium.com", {} }, + .{ "freetls.fastly.net", {} }, + .{ "map.fastly.net", {} }, + .{ "a.prod.fastly.net", {} }, + .{ "global.prod.fastly.net", {} }, + .{ "a.ssl.fastly.net", {} }, + .{ "b.ssl.fastly.net", {} }, + .{ "global.ssl.fastly.net", {} }, + .{ "fastlylb.net", {} }, + .{ "map.fastlylb.net", {} }, + .{ "*.user.fm", {} }, + .{ "fastvps-server.com", {} }, + .{ "fastvps.host", {} }, + .{ "myfast.host", {} }, + .{ "fastvps.site", {} }, + .{ "myfast.space", {} }, + .{ "conn.uk", {} }, + .{ "copro.uk", {} }, + .{ "hosp.uk", {} }, + .{ "fedorainfracloud.org", {} }, + .{ "fedorapeople.org", {} }, + .{ "cloud.fedoraproject.org", {} }, + .{ "app.os.fedoraproject.org", {} }, + .{ "app.os.stg.fedoraproject.org", {} }, + .{ "mydobiss.com", {} }, + .{ "fh-muenster.io", {} }, + .{ "filegear.me", {} }, + .{ "firebaseapp.com", {} }, + .{ "fldrv.com", {} }, + .{ "on-fleek.app", {} }, + .{ "flutterflow.app", {} }, + .{ "fly.dev", {} }, + .{ "shw.io", {} }, + .{ "edgeapp.net", {} }, + .{ "forgeblocks.com", {} }, + .{ "id.forgerock.io", {} }, + .{ "framer.ai", {} }, + .{ "framer.app", {} }, + .{ "framercanvas.com", {} }, + .{ "framer.media", {} }, + .{ "framer.photos", {} }, + .{ "framer.website", {} }, + .{ "framer.wiki", {} }, + .{ "*.0e.vc", {} }, + .{ "freebox-os.com", {} }, + .{ "freeboxos.com", {} }, + .{ "fbx-os.fr", {} }, + .{ "fbxos.fr", {} }, + .{ "freebox-os.fr", {} }, + .{ "freeboxos.fr", {} }, + .{ "freedesktop.org", {} }, + .{ "freemyip.com", {} }, + .{ "*.frusky.de", {} }, + .{ "wien.funkfeuer.at", {} }, + .{ "daemon.asia", {} }, + .{ "dix.asia", {} }, + .{ "mydns.bz", {} }, + .{ "0am.jp", {} }, + .{ "0g0.jp", {} }, + .{ "0j0.jp", {} }, + .{ "0t0.jp", {} }, + .{ "mydns.jp", {} }, + .{ "pgw.jp", {} }, + .{ "wjg.jp", {} }, + .{ "keyword-on.net", {} }, + .{ "live-on.net", {} }, + .{ "server-on.net", {} }, + .{ "mydns.tw", {} }, + .{ "mydns.vc", {} }, + .{ "*.futurecms.at", {} }, + .{ "*.ex.futurecms.at", {} }, + .{ "*.in.futurecms.at", {} }, + .{ "futurehosting.at", {} }, + .{ "futuremailing.at", {} }, + .{ "*.ex.ortsinfo.at", {} }, + .{ "*.kunden.ortsinfo.at", {} }, + .{ "*.statics.cloud", {} }, + .{ "aliases121.com", {} }, + .{ "campaign.gov.uk", {} }, + .{ "service.gov.uk", {} }, + .{ "independent-commission.uk", {} }, + .{ "independent-inquest.uk", {} }, + .{ "independent-inquiry.uk", {} }, + .{ "independent-panel.uk", {} }, + .{ "independent-review.uk", {} }, + .{ "public-inquiry.uk", {} }, + .{ "royal-commission.uk", {} }, + .{ "gehirn.ne.jp", {} }, + .{ "usercontent.jp", {} }, + .{ "gentapps.com", {} }, + .{ "gentlentapis.com", {} }, + .{ "cdn-edges.net", {} }, + .{ "gsj.bz", {} }, + .{ "githubusercontent.com", {} }, + .{ "githubpreview.dev", {} }, + .{ "github.io", {} }, + .{ "gitlab.io", {} }, + .{ "gitapp.si", {} }, + .{ "gitpage.si", {} }, + .{ "glitch.me", {} }, + .{ "nog.community", {} }, + .{ "co.ro", {} }, + .{ "shop.ro", {} }, + .{ "lolipop.io", {} }, + .{ "angry.jp", {} }, + .{ "babyblue.jp", {} }, + .{ "babymilk.jp", {} }, + .{ "backdrop.jp", {} }, + .{ "bambina.jp", {} }, + .{ "bitter.jp", {} }, + .{ "blush.jp", {} }, + .{ "boo.jp", {} }, + .{ "boy.jp", {} }, + .{ "boyfriend.jp", {} }, + .{ "but.jp", {} }, + .{ "candypop.jp", {} }, + .{ "capoo.jp", {} }, + .{ "catfood.jp", {} }, + .{ "cheap.jp", {} }, + .{ "chicappa.jp", {} }, + .{ "chillout.jp", {} }, + .{ "chips.jp", {} }, + .{ "chowder.jp", {} }, + .{ "chu.jp", {} }, + .{ "ciao.jp", {} }, + .{ "cocotte.jp", {} }, + .{ "coolblog.jp", {} }, + .{ "cranky.jp", {} }, + .{ "cutegirl.jp", {} }, + .{ "daa.jp", {} }, + .{ "deca.jp", {} }, + .{ "deci.jp", {} }, + .{ "digick.jp", {} }, + .{ "egoism.jp", {} }, + .{ "fakefur.jp", {} }, + .{ "fem.jp", {} }, + .{ "flier.jp", {} }, + .{ "floppy.jp", {} }, + .{ "fool.jp", {} }, + .{ "frenchkiss.jp", {} }, + .{ "girlfriend.jp", {} }, + .{ "girly.jp", {} }, + .{ "gloomy.jp", {} }, + .{ "gonna.jp", {} }, + .{ "greater.jp", {} }, + .{ "hacca.jp", {} }, + .{ "heavy.jp", {} }, + .{ "her.jp", {} }, + .{ "hiho.jp", {} }, + .{ "hippy.jp", {} }, + .{ "holy.jp", {} }, + .{ "hungry.jp", {} }, + .{ "icurus.jp", {} }, + .{ "itigo.jp", {} }, + .{ "jellybean.jp", {} }, + .{ "kikirara.jp", {} }, + .{ "kill.jp", {} }, + .{ "kilo.jp", {} }, + .{ "kuron.jp", {} }, + .{ "littlestar.jp", {} }, + .{ "lolipopmc.jp", {} }, + .{ "lolitapunk.jp", {} }, + .{ "lomo.jp", {} }, + .{ "lovepop.jp", {} }, + .{ "lovesick.jp", {} }, + .{ "main.jp", {} }, + .{ "mods.jp", {} }, + .{ "mond.jp", {} }, + .{ "mongolian.jp", {} }, + .{ "moo.jp", {} }, + .{ "namaste.jp", {} }, + .{ "nikita.jp", {} }, + .{ "nobushi.jp", {} }, + .{ "noor.jp", {} }, + .{ "oops.jp", {} }, + .{ "parallel.jp", {} }, + .{ "parasite.jp", {} }, + .{ "pecori.jp", {} }, + .{ "peewee.jp", {} }, + .{ "penne.jp", {} }, + .{ "pepper.jp", {} }, + .{ "perma.jp", {} }, + .{ "pigboat.jp", {} }, + .{ "pinoko.jp", {} }, + .{ "punyu.jp", {} }, + .{ "pupu.jp", {} }, + .{ "pussycat.jp", {} }, + .{ "pya.jp", {} }, + .{ "raindrop.jp", {} }, + .{ "readymade.jp", {} }, + .{ "sadist.jp", {} }, + .{ "schoolbus.jp", {} }, + .{ "secret.jp", {} }, + .{ "staba.jp", {} }, + .{ "stripper.jp", {} }, + .{ "sub.jp", {} }, + .{ "sunnyday.jp", {} }, + .{ "thick.jp", {} }, + .{ "tonkotsu.jp", {} }, + .{ "under.jp", {} }, + .{ "upper.jp", {} }, + .{ "velvet.jp", {} }, + .{ "verse.jp", {} }, + .{ "versus.jp", {} }, + .{ "vivian.jp", {} }, + .{ "watson.jp", {} }, + .{ "weblike.jp", {} }, + .{ "whitesnow.jp", {} }, + .{ "zombie.jp", {} }, + .{ "heteml.net", {} }, + .{ "graphic.design", {} }, + .{ "goip.de", {} }, + .{ "*.hosted.app", {} }, + .{ "*.run.app", {} }, + .{ "web.app", {} }, + .{ "*.0emm.com", {} }, + .{ "appspot.com", {} }, + .{ "*.r.appspot.com", {} }, + .{ "blogspot.com", {} }, + .{ "codespot.com", {} }, + .{ "googleapis.com", {} }, + .{ "googlecode.com", {} }, + .{ "pagespeedmobilizer.com", {} }, + .{ "withgoogle.com", {} }, + .{ "withyoutube.com", {} }, + .{ "*.gateway.dev", {} }, + .{ "cloud.goog", {} }, + .{ "translate.goog", {} }, + .{ "*.usercontent.goog", {} }, + .{ "cloudfunctions.net", {} }, + .{ "goupile.fr", {} }, + .{ "pymnt.uk", {} }, + .{ "cloudapps.digital", {} }, + .{ "london.cloudapps.digital", {} }, + .{ "gov.nl", {} }, + .{ "grafana-dev.net", {} }, + .{ "grayjayleagues.com", {} }, + .{ "günstigbestellen.de", {} }, + .{ "günstigliefern.de", {} }, + .{ "häkkinen.fi", {} }, + .{ "hrsn.dev", {} }, + .{ "hashbang.sh", {} }, + .{ "hasura.app", {} }, + .{ "hasura-app.io", {} }, + .{ "hatenablog.com", {} }, + .{ "hatenadiary.com", {} }, + .{ "hateblo.jp", {} }, + .{ "hatenablog.jp", {} }, + .{ "hatenadiary.jp", {} }, + .{ "hatenadiary.org", {} }, + .{ "pages.it.hs-heilbronn.de", {} }, + .{ "pages-research.it.hs-heilbronn.de", {} }, + .{ "heiyu.space", {} }, + .{ "helioho.st", {} }, + .{ "heliohost.us", {} }, + .{ "hepforge.org", {} }, + .{ "herokuapp.com", {} }, + .{ "heyflow.page", {} }, + .{ "heyflow.site", {} }, + .{ "ravendb.cloud", {} }, + .{ "ravendb.community", {} }, + .{ "development.run", {} }, + .{ "ravendb.run", {} }, + .{ "homesklep.pl", {} }, + .{ "*.kin.one", {} }, + .{ "*.id.pub", {} }, + .{ "*.kin.pub", {} }, + .{ "hoplix.shop", {} }, + .{ "orx.biz", {} }, + .{ "biz.gl", {} }, + .{ "biz.ng", {} }, + .{ "co.biz.ng", {} }, + .{ "dl.biz.ng", {} }, + .{ "go.biz.ng", {} }, + .{ "lg.biz.ng", {} }, + .{ "on.biz.ng", {} }, + .{ "col.ng", {} }, + .{ "firm.ng", {} }, + .{ "gen.ng", {} }, + .{ "ltd.ng", {} }, + .{ "ngo.ng", {} }, + .{ "plc.ng", {} }, + .{ "ie.ua", {} }, + .{ "hostyhosting.io", {} }, + .{ "hf.space", {} }, + .{ "static.hf.space", {} }, + .{ "hypernode.io", {} }, + .{ "iobb.net", {} }, + .{ "co.cz", {} }, + .{ "*.moonscale.io", {} }, + .{ "moonscale.net", {} }, + .{ "gr.com", {} }, + .{ "iki.fi", {} }, + .{ "ibxos.it", {} }, + .{ "iliadboxos.it", {} }, + .{ "smushcdn.com", {} }, + .{ "wphostedmail.com", {} }, + .{ "wpmucdn.com", {} }, + .{ "tempurl.host", {} }, + .{ "wpmudev.host", {} }, + .{ "dyn-berlin.de", {} }, + .{ "in-berlin.de", {} }, + .{ "in-brb.de", {} }, + .{ "in-butter.de", {} }, + .{ "in-dsl.de", {} }, + .{ "in-vpn.de", {} }, + .{ "in-dsl.net", {} }, + .{ "in-vpn.net", {} }, + .{ "in-dsl.org", {} }, + .{ "in-vpn.org", {} }, + .{ "biz.at", {} }, + .{ "info.at", {} }, + .{ "info.cx", {} }, + .{ "ac.leg.br", {} }, + .{ "al.leg.br", {} }, + .{ "am.leg.br", {} }, + .{ "ap.leg.br", {} }, + .{ "ba.leg.br", {} }, + .{ "ce.leg.br", {} }, + .{ "df.leg.br", {} }, + .{ "es.leg.br", {} }, + .{ "go.leg.br", {} }, + .{ "ma.leg.br", {} }, + .{ "mg.leg.br", {} }, + .{ "ms.leg.br", {} }, + .{ "mt.leg.br", {} }, + .{ "pa.leg.br", {} }, + .{ "pb.leg.br", {} }, + .{ "pe.leg.br", {} }, + .{ "pi.leg.br", {} }, + .{ "pr.leg.br", {} }, + .{ "rj.leg.br", {} }, + .{ "rn.leg.br", {} }, + .{ "ro.leg.br", {} }, + .{ "rr.leg.br", {} }, + .{ "rs.leg.br", {} }, + .{ "sc.leg.br", {} }, + .{ "se.leg.br", {} }, + .{ "sp.leg.br", {} }, + .{ "to.leg.br", {} }, + .{ "pixolino.com", {} }, + .{ "na4u.ru", {} }, + .{ "botdash.app", {} }, + .{ "botdash.dev", {} }, + .{ "botdash.gg", {} }, + .{ "botdash.net", {} }, + .{ "botda.sh", {} }, + .{ "botdash.xyz", {} }, + .{ "apps-1and1.com", {} }, + .{ "live-website.com", {} }, + .{ "apps-1and1.net", {} }, + .{ "websitebuilder.online", {} }, + .{ "app-ionos.space", {} }, + .{ "iopsys.se", {} }, + .{ "*.dweb.link", {} }, + .{ "ipifony.net", {} }, + .{ "ir.md", {} }, + .{ "is-a-good.dev", {} }, + .{ "is-a.dev", {} }, + .{ "iservschule.de", {} }, + .{ "mein-iserv.de", {} }, + .{ "schulplattform.de", {} }, + .{ "schulserver.de", {} }, + .{ "test-iserv.de", {} }, + .{ "iserv.dev", {} }, + .{ "mel.cloudlets.com.au", {} }, + .{ "cloud.interhostsolutions.be", {} }, + .{ "alp1.ae.flow.ch", {} }, + .{ "appengine.flow.ch", {} }, + .{ "es-1.axarnet.cloud", {} }, + .{ "diadem.cloud", {} }, + .{ "vip.jelastic.cloud", {} }, + .{ "jele.cloud", {} }, + .{ "it1.eur.aruba.jenv-aruba.cloud", {} }, + .{ "it1.jenv-aruba.cloud", {} }, + .{ "keliweb.cloud", {} }, + .{ "cs.keliweb.cloud", {} }, + .{ "oxa.cloud", {} }, + .{ "tn.oxa.cloud", {} }, + .{ "uk.oxa.cloud", {} }, + .{ "primetel.cloud", {} }, + .{ "uk.primetel.cloud", {} }, + .{ "ca.reclaim.cloud", {} }, + .{ "uk.reclaim.cloud", {} }, + .{ "us.reclaim.cloud", {} }, + .{ "ch.trendhosting.cloud", {} }, + .{ "de.trendhosting.cloud", {} }, + .{ "jele.club", {} }, + .{ "dopaas.com", {} }, + .{ "paas.hosted-by-previder.com", {} }, + .{ "rag-cloud.hosteur.com", {} }, + .{ "rag-cloud-ch.hosteur.com", {} }, + .{ "jcloud.ik-server.com", {} }, + .{ "jcloud-ver-jpc.ik-server.com", {} }, + .{ "demo.jelastic.com", {} }, + .{ "paas.massivegrid.com", {} }, + .{ "jed.wafaicloud.com", {} }, + .{ "ryd.wafaicloud.com", {} }, + .{ "j.scaleforce.com.cy", {} }, + .{ "jelastic.dogado.eu", {} }, + .{ "fi.cloudplatform.fi", {} }, + .{ "demo.datacenter.fi", {} }, + .{ "paas.datacenter.fi", {} }, + .{ "jele.host", {} }, + .{ "mircloud.host", {} }, + .{ "paas.beebyte.io", {} }, + .{ "sekd1.beebyteapp.io", {} }, + .{ "jele.io", {} }, + .{ "jc.neen.it", {} }, + .{ "jcloud.kz", {} }, + .{ "cloudjiffy.net", {} }, + .{ "fra1-de.cloudjiffy.net", {} }, + .{ "west1-us.cloudjiffy.net", {} }, + .{ "jls-sto1.elastx.net", {} }, + .{ "jls-sto2.elastx.net", {} }, + .{ "jls-sto3.elastx.net", {} }, + .{ "fr-1.paas.massivegrid.net", {} }, + .{ "lon-1.paas.massivegrid.net", {} }, + .{ "lon-2.paas.massivegrid.net", {} }, + .{ "ny-1.paas.massivegrid.net", {} }, + .{ "ny-2.paas.massivegrid.net", {} }, + .{ "sg-1.paas.massivegrid.net", {} }, + .{ "jelastic.saveincloud.net", {} }, + .{ "nordeste-idc.saveincloud.net", {} }, + .{ "j.scaleforce.net", {} }, + .{ "sdscloud.pl", {} }, + .{ "unicloud.pl", {} }, + .{ "mircloud.ru", {} }, + .{ "enscaled.sg", {} }, + .{ "jele.site", {} }, + .{ "jelastic.team", {} }, + .{ "orangecloud.tn", {} }, + .{ "j.layershift.co.uk", {} }, + .{ "phx.enscaled.us", {} }, + .{ "mircloud.us", {} }, + .{ "myjino.ru", {} }, + .{ "*.hosting.myjino.ru", {} }, + .{ "*.landing.myjino.ru", {} }, + .{ "*.spectrum.myjino.ru", {} }, + .{ "*.vps.myjino.ru", {} }, + .{ "jotelulu.cloud", {} }, + .{ "webadorsite.com", {} }, + .{ "jouwweb.site", {} }, + .{ "*.cns.joyent.com", {} }, + .{ "*.triton.zone", {} }, + .{ "js.org", {} }, + .{ "kaas.gg", {} }, + .{ "khplay.nl", {} }, + .{ "kapsi.fi", {} }, + .{ "ezproxy.kuleuven.be", {} }, + .{ "kuleuven.cloud", {} }, + .{ "keymachine.de", {} }, + .{ "kinghost.net", {} }, + .{ "uni5.net", {} }, + .{ "knightpoint.systems", {} }, + .{ "koobin.events", {} }, + .{ "webthings.io", {} }, + .{ "krellian.net", {} }, + .{ "oya.to", {} }, + .{ "laravel.cloud", {} }, + .{ "git-repos.de", {} }, + .{ "lcube-server.de", {} }, + .{ "svn-repos.de", {} }, + .{ "leadpages.co", {} }, + .{ "lpages.co", {} }, + .{ "lpusercontent.com", {} }, + .{ "liara.run", {} }, + .{ "iran.liara.run", {} }, + .{ "libp2p.direct", {} }, + .{ "runcontainers.dev", {} }, + .{ "co.business", {} }, + .{ "co.education", {} }, + .{ "co.events", {} }, + .{ "co.financial", {} }, + .{ "co.network", {} }, + .{ "co.place", {} }, + .{ "co.technology", {} }, + .{ "linkyard-cloud.ch", {} }, + .{ "linkyard.cloud", {} }, + .{ "members.linode.com", {} }, + .{ "*.nodebalancer.linode.com", {} }, + .{ "*.linodeobjects.com", {} }, + .{ "ip.linodeusercontent.com", {} }, + .{ "we.bs", {} }, + .{ "filegear-sg.me", {} }, + .{ "ggff.net", {} }, + .{ "*.user.localcert.dev", {} }, + .{ "localcert.net", {} }, + .{ "localhostcert.net", {} }, + .{ "localtonet.com", {} }, + .{ "*.localto.net", {} }, + .{ "lodz.pl", {} }, + .{ "pabianice.pl", {} }, + .{ "plock.pl", {} }, + .{ "sieradz.pl", {} }, + .{ "skierniewice.pl", {} }, + .{ "zgierz.pl", {} }, + .{ "loginline.app", {} }, + .{ "loginline.dev", {} }, + .{ "loginline.io", {} }, + .{ "loginline.services", {} }, + .{ "loginline.site", {} }, + .{ "lohmus.me", {} }, + .{ "servers.run", {} }, + .{ "lovable.app", {} }, + .{ "lovableproject.com", {} }, + .{ "krasnik.pl", {} }, + .{ "leczna.pl", {} }, + .{ "lubartow.pl", {} }, + .{ "lublin.pl", {} }, + .{ "poniatowa.pl", {} }, + .{ "swidnik.pl", {} }, + .{ "glug.org.uk", {} }, + .{ "lug.org.uk", {} }, + .{ "lugs.org.uk", {} }, + .{ "barsy.bg", {} }, + .{ "barsy.club", {} }, + .{ "barsycenter.com", {} }, + .{ "barsyonline.com", {} }, + .{ "barsy.de", {} }, + .{ "barsy.dev", {} }, + .{ "barsy.eu", {} }, + .{ "barsy.gr", {} }, + .{ "barsy.in", {} }, + .{ "barsy.info", {} }, + .{ "barsy.io", {} }, + .{ "barsy.me", {} }, + .{ "barsy.menu", {} }, + .{ "barsyonline.menu", {} }, + .{ "barsy.mobi", {} }, + .{ "barsy.net", {} }, + .{ "barsy.online", {} }, + .{ "barsy.org", {} }, + .{ "barsy.pro", {} }, + .{ "barsy.pub", {} }, + .{ "barsy.ro", {} }, + .{ "barsy.rs", {} }, + .{ "barsy.shop", {} }, + .{ "barsyonline.shop", {} }, + .{ "barsy.site", {} }, + .{ "barsy.store", {} }, + .{ "barsy.support", {} }, + .{ "barsy.uk", {} }, + .{ "barsy.co.uk", {} }, + .{ "barsyonline.co.uk", {} }, + .{ "*.magentosite.cloud", {} }, + .{ "hb.cldmail.ru", {} }, + .{ "matlab.cloud", {} }, + .{ "modelscape.com", {} }, + .{ "mwcloudnonprod.com", {} }, + .{ "polyspace.com", {} }, + .{ "mayfirst.info", {} }, + .{ "mayfirst.org", {} }, + .{ "mazeplay.com", {} }, + .{ "mcdir.me", {} }, + .{ "mcdir.ru", {} }, + .{ "vps.mcdir.ru", {} }, + .{ "mcpre.ru", {} }, + .{ "mediatech.by", {} }, + .{ "mediatech.dev", {} }, + .{ "hra.health", {} }, + .{ "medusajs.app", {} }, + .{ "miniserver.com", {} }, + .{ "memset.net", {} }, + .{ "messerli.app", {} }, + .{ "atmeta.com", {} }, + .{ "apps.fbsbx.com", {} }, + .{ "*.cloud.metacentrum.cz", {} }, + .{ "custom.metacentrum.cz", {} }, + .{ "flt.cloud.muni.cz", {} }, + .{ "usr.cloud.muni.cz", {} }, + .{ "meteorapp.com", {} }, + .{ "eu.meteorapp.com", {} }, + .{ "co.pl", {} }, + .{ "*.azurecontainer.io", {} }, + .{ "azure-api.net", {} }, + .{ "azure-mobile.net", {} }, + .{ "azureedge.net", {} }, + .{ "azurefd.net", {} }, + .{ "azurestaticapps.net", {} }, + .{ "1.azurestaticapps.net", {} }, + .{ "2.azurestaticapps.net", {} }, + .{ "3.azurestaticapps.net", {} }, + .{ "4.azurestaticapps.net", {} }, + .{ "5.azurestaticapps.net", {} }, + .{ "6.azurestaticapps.net", {} }, + .{ "7.azurestaticapps.net", {} }, + .{ "centralus.azurestaticapps.net", {} }, + .{ "eastasia.azurestaticapps.net", {} }, + .{ "eastus2.azurestaticapps.net", {} }, + .{ "westeurope.azurestaticapps.net", {} }, + .{ "westus2.azurestaticapps.net", {} }, + .{ "azurewebsites.net", {} }, + .{ "cloudapp.net", {} }, + .{ "trafficmanager.net", {} }, + .{ "blob.core.windows.net", {} }, + .{ "servicebus.windows.net", {} }, + .{ "routingthecloud.com", {} }, + .{ "sn.mynetname.net", {} }, + .{ "routingthecloud.net", {} }, + .{ "routingthecloud.org", {} }, + .{ "csx.cc", {} }, + .{ "mydbserver.com", {} }, + .{ "webspaceconfig.de", {} }, + .{ "mittwald.info", {} }, + .{ "mittwaldserver.info", {} }, + .{ "typo3server.info", {} }, + .{ "project.space", {} }, + .{ "modx.dev", {} }, + .{ "bmoattachments.org", {} }, + .{ "net.ru", {} }, + .{ "org.ru", {} }, + .{ "pp.ru", {} }, + .{ "hostedpi.com", {} }, + .{ "caracal.mythic-beasts.com", {} }, + .{ "customer.mythic-beasts.com", {} }, + .{ "fentiger.mythic-beasts.com", {} }, + .{ "lynx.mythic-beasts.com", {} }, + .{ "ocelot.mythic-beasts.com", {} }, + .{ "oncilla.mythic-beasts.com", {} }, + .{ "onza.mythic-beasts.com", {} }, + .{ "sphinx.mythic-beasts.com", {} }, + .{ "vs.mythic-beasts.com", {} }, + .{ "x.mythic-beasts.com", {} }, + .{ "yali.mythic-beasts.com", {} }, + .{ "cust.retrosnub.co.uk", {} }, + .{ "ui.nabu.casa", {} }, + .{ "cloud.nospamproxy.com", {} }, + .{ "o365.cloud.nospamproxy.com", {} }, + .{ "netlib.re", {} }, + .{ "netfy.app", {} }, + .{ "netlify.app", {} }, + .{ "4u.com", {} }, + .{ "nfshost.com", {} }, + .{ "ipfs.nftstorage.link", {} }, + .{ "ngo.us", {} }, + .{ "ngrok.app", {} }, + .{ "ngrok-free.app", {} }, + .{ "ngrok.dev", {} }, + .{ "ngrok-free.dev", {} }, + .{ "ngrok.io", {} }, + .{ "ap.ngrok.io", {} }, + .{ "au.ngrok.io", {} }, + .{ "eu.ngrok.io", {} }, + .{ "in.ngrok.io", {} }, + .{ "jp.ngrok.io", {} }, + .{ "sa.ngrok.io", {} }, + .{ "us.ngrok.io", {} }, + .{ "ngrok.pizza", {} }, + .{ "ngrok.pro", {} }, + .{ "torun.pl", {} }, + .{ "nh-serv.co.uk", {} }, + .{ "nimsite.uk", {} }, + .{ "mmafan.biz", {} }, + .{ "myftp.biz", {} }, + .{ "no-ip.biz", {} }, + .{ "no-ip.ca", {} }, + .{ "fantasyleague.cc", {} }, + .{ "gotdns.ch", {} }, + .{ "3utilities.com", {} }, + .{ "blogsyte.com", {} }, + .{ "ciscofreak.com", {} }, + .{ "damnserver.com", {} }, + .{ "ddnsking.com", {} }, + .{ "ditchyourip.com", {} }, + .{ "dnsiskinky.com", {} }, + .{ "dynns.com", {} }, + .{ "geekgalaxy.com", {} }, + .{ "health-carereform.com", {} }, + .{ "homesecuritymac.com", {} }, + .{ "homesecuritypc.com", {} }, + .{ "myactivedirectory.com", {} }, + .{ "mysecuritycamera.com", {} }, + .{ "myvnc.com", {} }, + .{ "net-freaks.com", {} }, + .{ "onthewifi.com", {} }, + .{ "point2this.com", {} }, + .{ "quicksytes.com", {} }, + .{ "securitytactics.com", {} }, + .{ "servebeer.com", {} }, + .{ "servecounterstrike.com", {} }, + .{ "serveexchange.com", {} }, + .{ "serveftp.com", {} }, + .{ "servegame.com", {} }, + .{ "servehalflife.com", {} }, + .{ "servehttp.com", {} }, + .{ "servehumour.com", {} }, + .{ "serveirc.com", {} }, + .{ "servemp3.com", {} }, + .{ "servep2p.com", {} }, + .{ "servepics.com", {} }, + .{ "servequake.com", {} }, + .{ "servesarcasm.com", {} }, + .{ "stufftoread.com", {} }, + .{ "unusualperson.com", {} }, + .{ "workisboring.com", {} }, + .{ "dvrcam.info", {} }, + .{ "ilovecollege.info", {} }, + .{ "no-ip.info", {} }, + .{ "brasilia.me", {} }, + .{ "ddns.me", {} }, + .{ "dnsfor.me", {} }, + .{ "hopto.me", {} }, + .{ "loginto.me", {} }, + .{ "noip.me", {} }, + .{ "webhop.me", {} }, + .{ "bounceme.net", {} }, + .{ "ddns.net", {} }, + .{ "eating-organic.net", {} }, + .{ "mydissent.net", {} }, + .{ "myeffect.net", {} }, + .{ "mymediapc.net", {} }, + .{ "mypsx.net", {} }, + .{ "mysecuritycamera.net", {} }, + .{ "nhlfan.net", {} }, + .{ "no-ip.net", {} }, + .{ "pgafan.net", {} }, + .{ "privatizehealthinsurance.net", {} }, + .{ "redirectme.net", {} }, + .{ "serveblog.net", {} }, + .{ "serveminecraft.net", {} }, + .{ "sytes.net", {} }, + .{ "cable-modem.org", {} }, + .{ "collegefan.org", {} }, + .{ "couchpotatofries.org", {} }, + .{ "hopto.org", {} }, + .{ "mlbfan.org", {} }, + .{ "myftp.org", {} }, + .{ "mysecuritycamera.org", {} }, + .{ "nflfan.org", {} }, + .{ "no-ip.org", {} }, + .{ "read-books.org", {} }, + .{ "ufcfan.org", {} }, + .{ "zapto.org", {} }, + .{ "no-ip.co.uk", {} }, + .{ "golffan.us", {} }, + .{ "noip.us", {} }, + .{ "pointto.us", {} }, + .{ "stage.nodeart.io", {} }, + .{ "*.developer.app", {} }, + .{ "noop.app", {} }, + .{ "*.northflank.app", {} }, + .{ "*.build.run", {} }, + .{ "*.code.run", {} }, + .{ "*.database.run", {} }, + .{ "*.migration.run", {} }, + .{ "noticeable.news", {} }, + .{ "notion.site", {} }, + .{ "dnsking.ch", {} }, + .{ "mypi.co", {} }, + .{ "myiphost.com", {} }, + .{ "forumz.info", {} }, + .{ "soundcast.me", {} }, + .{ "tcp4.me", {} }, + .{ "dnsup.net", {} }, + .{ "hicam.net", {} }, + .{ "now-dns.net", {} }, + .{ "ownip.net", {} }, + .{ "vpndns.net", {} }, + .{ "dynserv.org", {} }, + .{ "now-dns.org", {} }, + .{ "x443.pw", {} }, + .{ "ntdll.top", {} }, + .{ "freeddns.us", {} }, + .{ "nsupdate.info", {} }, + .{ "nerdpol.ovh", {} }, + .{ "nyc.mn", {} }, + .{ "prvcy.page", {} }, + .{ "obl.ong", {} }, + .{ "observablehq.cloud", {} }, + .{ "static.observableusercontent.com", {} }, + .{ "omg.lol", {} }, + .{ "cloudycluster.net", {} }, + .{ "omniwe.site", {} }, + .{ "123webseite.at", {} }, + .{ "123website.be", {} }, + .{ "simplesite.com.br", {} }, + .{ "123website.ch", {} }, + .{ "simplesite.com", {} }, + .{ "123webseite.de", {} }, + .{ "123hjemmeside.dk", {} }, + .{ "123miweb.es", {} }, + .{ "123kotisivu.fi", {} }, + .{ "123siteweb.fr", {} }, + .{ "simplesite.gr", {} }, + .{ "123homepage.it", {} }, + .{ "123website.lu", {} }, + .{ "123website.nl", {} }, + .{ "123hjemmeside.no", {} }, + .{ "service.one", {} }, + .{ "simplesite.pl", {} }, + .{ "123paginaweb.pt", {} }, + .{ "123minsida.se", {} }, + .{ "is-a-fullstack.dev", {} }, + .{ "is-cool.dev", {} }, + .{ "is-not-a.dev", {} }, + .{ "localplayer.dev", {} }, + .{ "is-local.org", {} }, + .{ "opensocial.site", {} }, + .{ "opencraft.hosting", {} }, + .{ "16-b.it", {} }, + .{ "32-b.it", {} }, + .{ "64-b.it", {} }, + .{ "orsites.com", {} }, + .{ "operaunite.com", {} }, + .{ "*.customer-oci.com", {} }, + .{ "*.oci.customer-oci.com", {} }, + .{ "*.ocp.customer-oci.com", {} }, + .{ "*.ocs.customer-oci.com", {} }, + .{ "*.oraclecloudapps.com", {} }, + .{ "*.oraclegovcloudapps.com", {} }, + .{ "*.oraclegovcloudapps.uk", {} }, + .{ "tech.orange", {} }, + .{ "can.re", {} }, + .{ "authgear-staging.com", {} }, + .{ "authgearapps.com", {} }, + .{ "skygearapp.com", {} }, + .{ "outsystemscloud.com", {} }, + .{ "*.hosting.ovh.net", {} }, + .{ "*.webpaas.ovh.net", {} }, + .{ "ownprovider.com", {} }, + .{ "own.pm", {} }, + .{ "*.owo.codes", {} }, + .{ "ox.rs", {} }, + .{ "oy.lc", {} }, + .{ "pgfog.com", {} }, + .{ "pagexl.com", {} }, + .{ "gotpantheon.com", {} }, + .{ "pantheonsite.io", {} }, + .{ "*.paywhirl.com", {} }, + .{ "*.xmit.co", {} }, + .{ "xmit.dev", {} }, + .{ "madethis.site", {} }, + .{ "srv.us", {} }, + .{ "gh.srv.us", {} }, + .{ "gl.srv.us", {} }, + .{ "lk3.ru", {} }, + .{ "mypep.link", {} }, + .{ "perspecta.cloud", {} }, + .{ "on-web.fr", {} }, + .{ "*.upsun.app", {} }, + .{ "upsunapp.com", {} }, + .{ "ent.platform.sh", {} }, + .{ "eu.platform.sh", {} }, + .{ "us.platform.sh", {} }, + .{ "*.platformsh.site", {} }, + .{ "*.tst.site", {} }, + .{ "platter-app.dev", {} }, + .{ "platterp.us", {} }, + .{ "pley.games", {} }, + .{ "onporter.run", {} }, + .{ "co.bn", {} }, + .{ "postman-echo.com", {} }, + .{ "pstmn.io", {} }, + .{ "mock.pstmn.io", {} }, + .{ "httpbin.org", {} }, + .{ "prequalifyme.today", {} }, + .{ "xen.prgmr.com", {} }, + .{ "priv.at", {} }, + .{ "protonet.io", {} }, + .{ "sub.psl.hrsn.dev", {} }, + .{ "*.wc.psl.hrsn.dev", {} }, + .{ "!ignored.wc.psl.hrsn.dev", {} }, + .{ "*.sub.wc.psl.hrsn.dev", {} }, + .{ "!ignored.sub.wc.psl.hrsn.dev", {} }, + .{ "chirurgiens-dentistes-en-france.fr", {} }, + .{ "byen.site", {} }, + .{ "pubtls.org", {} }, + .{ "pythonanywhere.com", {} }, + .{ "eu.pythonanywhere.com", {} }, + .{ "qa2.com", {} }, + .{ "qcx.io", {} }, + .{ "*.sys.qcx.io", {} }, + .{ "myqnapcloud.cn", {} }, + .{ "alpha-myqnapcloud.com", {} }, + .{ "dev-myqnapcloud.com", {} }, + .{ "mycloudnas.com", {} }, + .{ "mynascloud.com", {} }, + .{ "myqnapcloud.com", {} }, + .{ "qoto.io", {} }, + .{ "qualifioapp.com", {} }, + .{ "ladesk.com", {} }, + .{ "qbuser.com", {} }, + .{ "*.quipelements.com", {} }, + .{ "vapor.cloud", {} }, + .{ "vaporcloud.io", {} }, + .{ "rackmaze.com", {} }, + .{ "rackmaze.net", {} }, + .{ "cloudsite.builders", {} }, + .{ "myradweb.net", {} }, + .{ "servername.us", {} }, + .{ "web.in", {} }, + .{ "in.net", {} }, + .{ "myrdbx.io", {} }, + .{ "site.rb-hosting.io", {} }, + .{ "*.on-rancher.cloud", {} }, + .{ "*.on-k3s.io", {} }, + .{ "*.on-rio.io", {} }, + .{ "ravpage.co.il", {} }, + .{ "readthedocs-hosted.com", {} }, + .{ "readthedocs.io", {} }, + .{ "rhcloud.com", {} }, + .{ "instances.spawn.cc", {} }, + .{ "onrender.com", {} }, + .{ "app.render.com", {} }, + .{ "replit.app", {} }, + .{ "id.replit.app", {} }, + .{ "firewalledreplit.co", {} }, + .{ "id.firewalledreplit.co", {} }, + .{ "repl.co", {} }, + .{ "id.repl.co", {} }, + .{ "replit.dev", {} }, + .{ "archer.replit.dev", {} }, + .{ "bones.replit.dev", {} }, + .{ "canary.replit.dev", {} }, + .{ "global.replit.dev", {} }, + .{ "hacker.replit.dev", {} }, + .{ "id.replit.dev", {} }, + .{ "janeway.replit.dev", {} }, + .{ "kim.replit.dev", {} }, + .{ "kira.replit.dev", {} }, + .{ "kirk.replit.dev", {} }, + .{ "odo.replit.dev", {} }, + .{ "paris.replit.dev", {} }, + .{ "picard.replit.dev", {} }, + .{ "pike.replit.dev", {} }, + .{ "prerelease.replit.dev", {} }, + .{ "reed.replit.dev", {} }, + .{ "riker.replit.dev", {} }, + .{ "sisko.replit.dev", {} }, + .{ "spock.replit.dev", {} }, + .{ "staging.replit.dev", {} }, + .{ "sulu.replit.dev", {} }, + .{ "tarpit.replit.dev", {} }, + .{ "teams.replit.dev", {} }, + .{ "tucker.replit.dev", {} }, + .{ "wesley.replit.dev", {} }, + .{ "worf.replit.dev", {} }, + .{ "repl.run", {} }, + .{ "resindevice.io", {} }, + .{ "devices.resinstaging.io", {} }, + .{ "hzc.io", {} }, + .{ "adimo.co.uk", {} }, + .{ "itcouldbewor.se", {} }, + .{ "aus.basketball", {} }, + .{ "nz.basketball", {} }, + .{ "subsc-pay.com", {} }, + .{ "subsc-pay.net", {} }, + .{ "git-pages.rit.edu", {} }, + .{ "rocky.page", {} }, + .{ "rub.de", {} }, + .{ "ruhr-uni-bochum.de", {} }, + .{ "io.noc.ruhr-uni-bochum.de", {} }, + .{ "биз.рус", {} }, + .{ "ком.рус", {} }, + .{ "крым.рус", {} }, + .{ "мир.рус", {} }, + .{ "мск.рус", {} }, + .{ "орг.рус", {} }, + .{ "самара.рус", {} }, + .{ "сочи.рус", {} }, + .{ "спб.рус", {} }, + .{ "я.рус", {} }, + .{ "ras.ru", {} }, + .{ "nyat.app", {} }, + .{ "180r.com", {} }, + .{ "dojin.com", {} }, + .{ "sakuratan.com", {} }, + .{ "sakuraweb.com", {} }, + .{ "x0.com", {} }, + .{ "2-d.jp", {} }, + .{ "bona.jp", {} }, + .{ "crap.jp", {} }, + .{ "daynight.jp", {} }, + .{ "eek.jp", {} }, + .{ "flop.jp", {} }, + .{ "halfmoon.jp", {} }, + .{ "jeez.jp", {} }, + .{ "matrix.jp", {} }, + .{ "mimoza.jp", {} }, + .{ "ivory.ne.jp", {} }, + .{ "mail-box.ne.jp", {} }, + .{ "mints.ne.jp", {} }, + .{ "mokuren.ne.jp", {} }, + .{ "opal.ne.jp", {} }, + .{ "sakura.ne.jp", {} }, + .{ "sumomo.ne.jp", {} }, + .{ "topaz.ne.jp", {} }, + .{ "netgamers.jp", {} }, + .{ "nyanta.jp", {} }, + .{ "o0o0.jp", {} }, + .{ "rdy.jp", {} }, + .{ "rgr.jp", {} }, + .{ "rulez.jp", {} }, + .{ "s3.isk01.sakurastorage.jp", {} }, + .{ "s3.isk02.sakurastorage.jp", {} }, + .{ "saloon.jp", {} }, + .{ "sblo.jp", {} }, + .{ "skr.jp", {} }, + .{ "tank.jp", {} }, + .{ "uh-oh.jp", {} }, + .{ "undo.jp", {} }, + .{ "rs.webaccel.jp", {} }, + .{ "user.webaccel.jp", {} }, + .{ "websozai.jp", {} }, + .{ "xii.jp", {} }, + .{ "squares.net", {} }, + .{ "jpn.org", {} }, + .{ "kirara.st", {} }, + .{ "x0.to", {} }, + .{ "from.tv", {} }, + .{ "sakura.tv", {} }, + .{ "*.builder.code.com", {} }, + .{ "*.dev-builder.code.com", {} }, + .{ "*.stg-builder.code.com", {} }, + .{ "*.001.test.code-builder-stg.platform.salesforce.com", {} }, + .{ "*.d.crm.dev", {} }, + .{ "*.w.crm.dev", {} }, + .{ "*.wa.crm.dev", {} }, + .{ "*.wb.crm.dev", {} }, + .{ "*.wc.crm.dev", {} }, + .{ "*.wd.crm.dev", {} }, + .{ "*.we.crm.dev", {} }, + .{ "*.wf.crm.dev", {} }, + .{ "sandcats.io", {} }, + .{ "logoip.com", {} }, + .{ "logoip.de", {} }, + .{ "fr-par-1.baremetal.scw.cloud", {} }, + .{ "fr-par-2.baremetal.scw.cloud", {} }, + .{ "nl-ams-1.baremetal.scw.cloud", {} }, + .{ "cockpit.fr-par.scw.cloud", {} }, + .{ "fnc.fr-par.scw.cloud", {} }, + .{ "functions.fnc.fr-par.scw.cloud", {} }, + .{ "k8s.fr-par.scw.cloud", {} }, + .{ "nodes.k8s.fr-par.scw.cloud", {} }, + .{ "s3.fr-par.scw.cloud", {} }, + .{ "s3-website.fr-par.scw.cloud", {} }, + .{ "whm.fr-par.scw.cloud", {} }, + .{ "priv.instances.scw.cloud", {} }, + .{ "pub.instances.scw.cloud", {} }, + .{ "k8s.scw.cloud", {} }, + .{ "cockpit.nl-ams.scw.cloud", {} }, + .{ "k8s.nl-ams.scw.cloud", {} }, + .{ "nodes.k8s.nl-ams.scw.cloud", {} }, + .{ "s3.nl-ams.scw.cloud", {} }, + .{ "s3-website.nl-ams.scw.cloud", {} }, + .{ "whm.nl-ams.scw.cloud", {} }, + .{ "cockpit.pl-waw.scw.cloud", {} }, + .{ "k8s.pl-waw.scw.cloud", {} }, + .{ "nodes.k8s.pl-waw.scw.cloud", {} }, + .{ "s3.pl-waw.scw.cloud", {} }, + .{ "s3-website.pl-waw.scw.cloud", {} }, + .{ "scalebook.scw.cloud", {} }, + .{ "smartlabeling.scw.cloud", {} }, + .{ "dedibox.fr", {} }, + .{ "schokokeks.net", {} }, + .{ "gov.scot", {} }, + .{ "service.gov.scot", {} }, + .{ "scrysec.com", {} }, + .{ "client.scrypted.io", {} }, + .{ "firewall-gateway.com", {} }, + .{ "firewall-gateway.de", {} }, + .{ "my-gateway.de", {} }, + .{ "my-router.de", {} }, + .{ "spdns.de", {} }, + .{ "spdns.eu", {} }, + .{ "firewall-gateway.net", {} }, + .{ "my-firewall.org", {} }, + .{ "myfirewall.org", {} }, + .{ "spdns.org", {} }, + .{ "seidat.net", {} }, + .{ "sellfy.store", {} }, + .{ "minisite.ms", {} }, + .{ "senseering.net", {} }, + .{ "servebolt.cloud", {} }, + .{ "biz.ua", {} }, + .{ "co.ua", {} }, + .{ "pp.ua", {} }, + .{ "as.sh.cn", {} }, + .{ "sheezy.games", {} }, + .{ "myshopblocks.com", {} }, + .{ "myshopify.com", {} }, + .{ "shopitsite.com", {} }, + .{ "shopware.shop", {} }, + .{ "shopware.store", {} }, + .{ "mo-siemens.io", {} }, + .{ "1kapp.com", {} }, + .{ "appchizi.com", {} }, + .{ "applinzi.com", {} }, + .{ "sinaapp.com", {} }, + .{ "vipsinaapp.com", {} }, + .{ "siteleaf.net", {} }, + .{ "small-web.org", {} }, + .{ "aeroport.fr", {} }, + .{ "avocat.fr", {} }, + .{ "chambagri.fr", {} }, + .{ "chirurgiens-dentistes.fr", {} }, + .{ "experts-comptables.fr", {} }, + .{ "medecin.fr", {} }, + .{ "notaires.fr", {} }, + .{ "pharmacien.fr", {} }, + .{ "port.fr", {} }, + .{ "veterinaire.fr", {} }, + .{ "vp4.me", {} }, + .{ "*.snowflake.app", {} }, + .{ "*.privatelink.snowflake.app", {} }, + .{ "streamlit.app", {} }, + .{ "streamlitapp.com", {} }, + .{ "try-snowplow.com", {} }, + .{ "mafelo.net", {} }, + .{ "playstation-cloud.com", {} }, + .{ "srht.site", {} }, + .{ "apps.lair.io", {} }, + .{ "*.stolos.io", {} }, + .{ "ind.mom", {} }, + .{ "customer.speedpartner.de", {} }, + .{ "myspreadshop.at", {} }, + .{ "myspreadshop.com.au", {} }, + .{ "myspreadshop.be", {} }, + .{ "myspreadshop.ca", {} }, + .{ "myspreadshop.ch", {} }, + .{ "myspreadshop.com", {} }, + .{ "myspreadshop.de", {} }, + .{ "myspreadshop.dk", {} }, + .{ "myspreadshop.es", {} }, + .{ "myspreadshop.fi", {} }, + .{ "myspreadshop.fr", {} }, + .{ "myspreadshop.ie", {} }, + .{ "myspreadshop.it", {} }, + .{ "myspreadshop.net", {} }, + .{ "myspreadshop.nl", {} }, + .{ "myspreadshop.no", {} }, + .{ "myspreadshop.pl", {} }, + .{ "myspreadshop.se", {} }, + .{ "myspreadshop.co.uk", {} }, + .{ "w-corp-staticblitz.com", {} }, + .{ "w-credentialless-staticblitz.com", {} }, + .{ "w-staticblitz.com", {} }, + .{ "stackhero-network.com", {} }, + .{ "runs.onstackit.cloud", {} }, + .{ "stackit.gg", {} }, + .{ "stackit.rocks", {} }, + .{ "stackit.run", {} }, + .{ "stackit.zone", {} }, + .{ "musician.io", {} }, + .{ "novecore.site", {} }, + .{ "api.stdlib.com", {} }, + .{ "feedback.ac", {} }, + .{ "forms.ac", {} }, + .{ "assessments.cx", {} }, + .{ "calculators.cx", {} }, + .{ "funnels.cx", {} }, + .{ "paynow.cx", {} }, + .{ "quizzes.cx", {} }, + .{ "researched.cx", {} }, + .{ "tests.cx", {} }, + .{ "surveys.so", {} }, + .{ "storebase.store", {} }, + .{ "storipress.app", {} }, + .{ "storj.farm", {} }, + .{ "strapiapp.com", {} }, + .{ "media.strapiapp.com", {} }, + .{ "vps-host.net", {} }, + .{ "atl.jelastic.vps-host.net", {} }, + .{ "njs.jelastic.vps-host.net", {} }, + .{ "ric.jelastic.vps-host.net", {} }, + .{ "streak-link.com", {} }, + .{ "streaklinks.com", {} }, + .{ "streakusercontent.com", {} }, + .{ "soc.srcf.net", {} }, + .{ "user.srcf.net", {} }, + .{ "utwente.io", {} }, + .{ "temp-dns.com", {} }, + .{ "supabase.co", {} }, + .{ "supabase.in", {} }, + .{ "supabase.net", {} }, + .{ "syncloud.it", {} }, + .{ "dscloud.biz", {} }, + .{ "direct.quickconnect.cn", {} }, + .{ "dsmynas.com", {} }, + .{ "familyds.com", {} }, + .{ "diskstation.me", {} }, + .{ "dscloud.me", {} }, + .{ "i234.me", {} }, + .{ "myds.me", {} }, + .{ "synology.me", {} }, + .{ "dscloud.mobi", {} }, + .{ "dsmynas.net", {} }, + .{ "familyds.net", {} }, + .{ "dsmynas.org", {} }, + .{ "familyds.org", {} }, + .{ "direct.quickconnect.to", {} }, + .{ "vpnplus.to", {} }, + .{ "mytabit.com", {} }, + .{ "mytabit.co.il", {} }, + .{ "tabitorder.co.il", {} }, + .{ "taifun-dns.de", {} }, + .{ "ts.net", {} }, + .{ "*.c.ts.net", {} }, + .{ "gda.pl", {} }, + .{ "gdansk.pl", {} }, + .{ "gdynia.pl", {} }, + .{ "med.pl", {} }, + .{ "sopot.pl", {} }, + .{ "taveusercontent.com", {} }, + .{ "p.tawk.email", {} }, + .{ "p.tawkto.email", {} }, + .{ "site.tb-hosting.com", {} }, + .{ "edugit.io", {} }, + .{ "s3.teckids.org", {} }, + .{ "telebit.app", {} }, + .{ "telebit.io", {} }, + .{ "*.telebit.xyz", {} }, + .{ "*.firenet.ch", {} }, + .{ "*.svc.firenet.ch", {} }, + .{ "reservd.com", {} }, + .{ "thingdustdata.com", {} }, + .{ "cust.dev.thingdust.io", {} }, + .{ "reservd.dev.thingdust.io", {} }, + .{ "cust.disrec.thingdust.io", {} }, + .{ "reservd.disrec.thingdust.io", {} }, + .{ "cust.prod.thingdust.io", {} }, + .{ "cust.testing.thingdust.io", {} }, + .{ "reservd.testing.thingdust.io", {} }, + .{ "tickets.io", {} }, + .{ "arvo.network", {} }, + .{ "azimuth.network", {} }, + .{ "tlon.network", {} }, + .{ "torproject.net", {} }, + .{ "pages.torproject.net", {} }, + .{ "townnews-staging.com", {} }, + .{ "12hp.at", {} }, + .{ "2ix.at", {} }, + .{ "4lima.at", {} }, + .{ "lima-city.at", {} }, + .{ "12hp.ch", {} }, + .{ "2ix.ch", {} }, + .{ "4lima.ch", {} }, + .{ "lima-city.ch", {} }, + .{ "trafficplex.cloud", {} }, + .{ "de.cool", {} }, + .{ "12hp.de", {} }, + .{ "2ix.de", {} }, + .{ "4lima.de", {} }, + .{ "lima-city.de", {} }, + .{ "1337.pictures", {} }, + .{ "clan.rip", {} }, + .{ "lima-city.rocks", {} }, + .{ "webspace.rocks", {} }, + .{ "lima.zone", {} }, + .{ "*.transurl.be", {} }, + .{ "*.transurl.eu", {} }, + .{ "site.transip.me", {} }, + .{ "*.transurl.nl", {} }, + .{ "tuxfamily.org", {} }, + .{ "dd-dns.de", {} }, + .{ "dray-dns.de", {} }, + .{ "draydns.de", {} }, + .{ "dyn-vpn.de", {} }, + .{ "dynvpn.de", {} }, + .{ "mein-vigor.de", {} }, + .{ "my-vigor.de", {} }, + .{ "my-wan.de", {} }, + .{ "syno-ds.de", {} }, + .{ "synology-diskstation.de", {} }, + .{ "synology-ds.de", {} }, + .{ "diskstation.eu", {} }, + .{ "diskstation.org", {} }, + .{ "typedream.app", {} }, + .{ "pro.typeform.com", {} }, + .{ "*.uberspace.de", {} }, + .{ "uber.space", {} }, + .{ "hk.com", {} }, + .{ "inc.hk", {} }, + .{ "ltd.hk", {} }, + .{ "hk.org", {} }, + .{ "it.com", {} }, + .{ "unison-services.cloud", {} }, + .{ "virtual-user.de", {} }, + .{ "virtualuser.de", {} }, + .{ "obj.ag", {} }, + .{ "name.pm", {} }, + .{ "sch.tf", {} }, + .{ "biz.wf", {} }, + .{ "sch.wf", {} }, + .{ "org.yt", {} }, + .{ "rs.ba", {} }, + .{ "bielsko.pl", {} }, + .{ "urown.cloud", {} }, + .{ "dnsupdate.info", {} }, + .{ "us.org", {} }, + .{ "v.ua", {} }, + .{ "express.val.run", {} }, + .{ "web.val.run", {} }, + .{ "vercel.app", {} }, + .{ "v0.build", {} }, + .{ "vercel.dev", {} }, + .{ "vusercontent.net", {} }, + .{ "now.sh", {} }, + .{ "2038.io", {} }, + .{ "router.management", {} }, + .{ "v-info.info", {} }, + .{ "voorloper.cloud", {} }, + .{ "*.vultrobjects.com", {} }, + .{ "wafflecell.com", {} }, + .{ "webflow.io", {} }, + .{ "webflowtest.io", {} }, + .{ "*.webhare.dev", {} }, + .{ "bookonline.app", {} }, + .{ "hotelwithflight.com", {} }, + .{ "reserve-online.com", {} }, + .{ "reserve-online.net", {} }, + .{ "cprapid.com", {} }, + .{ "pleskns.com", {} }, + .{ "wp2.host", {} }, + .{ "pdns.page", {} }, + .{ "plesk.page", {} }, + .{ "wpsquared.site", {} }, + .{ "*.wadl.top", {} }, + .{ "remotewd.com", {} }, + .{ "box.ca", {} }, + .{ "pages.wiardweb.com", {} }, + .{ "toolforge.org", {} }, + .{ "wmcloud.org", {} }, + .{ "wmflabs.org", {} }, + .{ "wdh.app", {} }, + .{ "panel.gg", {} }, + .{ "daemon.panel.gg", {} }, + .{ "wixsite.com", {} }, + .{ "wixstudio.com", {} }, + .{ "editorx.io", {} }, + .{ "wixstudio.io", {} }, + .{ "wix.run", {} }, + .{ "messwithdns.com", {} }, + .{ "woltlab-demo.com", {} }, + .{ "myforum.community", {} }, + .{ "community-pro.de", {} }, + .{ "diskussionsbereich.de", {} }, + .{ "community-pro.net", {} }, + .{ "meinforum.net", {} }, + .{ "affinitylottery.org.uk", {} }, + .{ "raffleentry.org.uk", {} }, + .{ "weeklylottery.org.uk", {} }, + .{ "wpenginepowered.com", {} }, + .{ "js.wpenginepowered.com", {} }, + .{ "half.host", {} }, + .{ "xnbay.com", {} }, + .{ "u2.xnbay.com", {} }, + .{ "u2-local.xnbay.com", {} }, + .{ "cistron.nl", {} }, + .{ "demon.nl", {} }, + .{ "xs4all.space", {} }, + .{ "yandexcloud.net", {} }, + .{ "storage.yandexcloud.net", {} }, + .{ "website.yandexcloud.net", {} }, + .{ "official.academy", {} }, + .{ "yolasite.com", {} }, + .{ "ynh.fr", {} }, + .{ "nohost.me", {} }, + .{ "noho.st", {} }, + .{ "za.net", {} }, + .{ "za.org", {} }, + .{ "zap.cloud", {} }, + .{ "zeabur.app", {} }, + .{ "*.zerops.app", {} }, + .{ "bss.design", {} }, + .{ "basicserver.io", {} }, + .{ "virtualserver.io", {} }, + .{ "enterprisecloud.nu", {} }, +}); diff --git a/src/data/public_suffix_list_gen.go b/src/data/public_suffix_list_gen.go new file mode 100644 index 00000000..137df6df --- /dev/null +++ b/src/data/public_suffix_list_gen.go @@ -0,0 +1,42 @@ +package main + +import ( + "bufio" + "fmt" + "net/http" + "strings" +) + +func main() { + resp, err := http.Get("https://publicsuffix.org/list/public_suffix_list.dat") + if err != nil { + panic(err) + } + defer resp.Body.Close() + + var domains []string + + scanner := bufio.NewScanner(resp.Body) + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + if len(line) == 0 || strings.HasPrefix(line, "//") { + continue + } + + domains = append(domains, line) + } + + lookup := + "const std = @import(\"std\");\n\n" + + "pub fn lookup(value: []const u8) bool {\n" + + " return public_suffix_list.has(value);\n" + + "}\n" + fmt.Println(lookup) + + fmt.Println("const public_suffix_list = std.StaticStringMap(void).initComptime([_]struct { []const u8, void }{") + for _, domain := range domains { + fmt.Printf(` .{ "%s", {} },`, domain) + fmt.Println() + } + fmt.Println("});") +} diff --git a/src/datetime.zig b/src/datetime.zig new file mode 100644 index 00000000..d54ff330 --- /dev/null +++ b/src/datetime.zig @@ -0,0 +1,2086 @@ +const std = @import("std"); + +const Allocator = std.mem.Allocator; + +pub const Date = struct { + year: i16, + month: u8, + day: u8, + + pub const Format = enum { + iso8601, + rfc3339, + }; + + pub fn init(year: i16, month: u8, day: u8) !Date { + if (!Date.valid(year, month, day)) { + return error.InvalidDate; + } + + return .{ + .year = year, + .month = month, + .day = day, + }; + } + + pub fn valid(year: i16, month: u8, day: u8) bool { + if (month == 0 or month > 12) { + return false; + } + + if (day == 0) { + return false; + } + + const month_days = [_]u8{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + const max_days = if (month == 2 and (@rem(year, 400) == 0 or (@rem(year, 100) != 0 and @rem(year, 4) == 0))) 29 else month_days[month - 1]; + if (day > max_days) { + return false; + } + + return true; + } + + pub fn parse(input: []const u8, fmt: Format) !Date { + var parser = Parser.init(input); + + const date = switch (fmt) { + .rfc3339 => try parser.rfc3339Date(), + .iso8601 => try parser.iso8601Date(), + }; + + if (parser.unconsumed() != 0) { + return error.InvalidDate; + } + + return date; + } + + pub fn order(a: Date, b: Date) std.math.Order { + const year_order = std.math.order(a.year, b.year); + if (year_order != .eq) return year_order; + + const month_order = std.math.order(a.month, b.month); + if (month_order != .eq) return month_order; + + return std.math.order(a.day, b.day); + } + + pub fn format(self: Date, comptime _: []const u8, _: std.fmt.FormatOptions, out: anytype) !void { + var buf: [11]u8 = undefined; + const n = writeDate(&buf, self); + try out.writeAll(buf[0..n]); + } + + pub fn jsonStringify(self: Date, out: anytype) !void { + // Our goal here isn't to validate the date. It's to write what we have + // in a YYYY-MM-DD format. If the data in Date isn't valid, that's not + // our problem and we don't guarantee any reasonable output in such cases. + + // std.fmt.formatInt is difficult to work with. The padding with signs + // doesn't work and it'll always put a + sign given a signed integer with padding + // So, for year, we always feed it an unsigned number (which avoids both issues) + // and prepend the - if we need it.s + var buf: [13]u8 = undefined; + const n = writeDate(buf[1..12], self); + buf[0] = '"'; + buf[n + 1] = '"'; + try out.print("{s}", .{buf[0 .. n + 2]}); + } + + pub fn jsonParse(allocator: Allocator, source: anytype, options: anytype) !Date { + _ = options; + + switch (try source.nextAlloc(allocator, .alloc_if_needed)) { + inline .string, .allocated_string => |str| return Date.parse(str, .rfc3339) catch return error.InvalidCharacter, + else => return error.UnexpectedToken, + } + } +}; + +pub const Time = struct { + hour: u8, + min: u8, + sec: u8, + micros: u32, + + pub const Format = enum { + rfc3339, + }; + + pub fn init(hour: u8, min: u8, sec: u8, micros: u32) !Time { + if (!Time.valid(hour, min, sec, micros)) { + return error.InvalidTime; + } + + return .{ + .hour = hour, + .min = min, + .sec = sec, + .micros = micros, + }; + } + + pub fn valid(hour: u8, min: u8, sec: u8, micros: u32) bool { + if (hour > 23) { + return false; + } + + if (min > 59) { + return false; + } + + if (sec > 59) { + return false; + } + + if (micros > 999999) { + return false; + } + + return true; + } + + pub fn parse(input: []const u8, fmt: Format) !Time { + var parser = Parser.init(input); + const time = switch (fmt) { + .rfc3339 => try parser.time(true), + }; + + if (parser.unconsumed() != 0) { + return error.InvalidTime; + } + return time; + } + + pub fn order(a: Time, b: Time) std.math.Order { + const hour_order = std.math.order(a.hour, b.hour); + if (hour_order != .eq) return hour_order; + + const min_order = std.math.order(a.min, b.min); + if (min_order != .eq) return min_order; + + const sec_order = std.math.order(a.sec, b.sec); + if (sec_order != .eq) return sec_order; + + return std.math.order(a.micros, b.micros); + } + + pub fn format(self: Time, comptime _: []const u8, _: std.fmt.FormatOptions, out: anytype) !void { + var buf: [15]u8 = undefined; + const n = writeTime(&buf, self); + try out.writeAll(buf[0..n]); + } + + pub fn jsonStringify(self: Time, out: anytype) !void { + // Our goal here isn't to validate the time. It's to write what we have + // in a hh:mm:ss.sss format. If the data in Time isn't valid, that's not + // our problem and we don't guarantee any reasonable output in such cases. + var buf: [17]u8 = undefined; + const n = writeTime(buf[1..16], self); + buf[0] = '"'; + buf[n + 1] = '"'; + try out.print("{s}", .{buf[0 .. n + 2]}); + } + + pub fn jsonParse(allocator: Allocator, source: anytype, options: anytype) !Time { + _ = options; + + switch (try source.nextAlloc(allocator, .alloc_if_needed)) { + inline .string, .allocated_string => |str| return Time.parse(str, .rfc3339) catch return error.InvalidCharacter, + else => return error.UnexpectedToken, + } + } +}; + +pub const DateTime = struct { + micros: i64, + + const MICROSECONDS_IN_A_DAY = 86_400_000_000; + const MICROSECONDS_IN_AN_HOUR = 3_600_000_000; + const MICROSECONDS_IN_A_MIN = 60_000_000; + const MICROSECONDS_IN_A_SEC = 1_000_000; + + pub const Format = enum { + rfc822, + rfc3339, + }; + + pub const TimestampPrecision = enum { + seconds, + milliseconds, + microseconds, + }; + + pub const TimeUnit = enum { + days, + hours, + minutes, + seconds, + milliseconds, + microseconds, + }; + + // https://blog.reverberate.org/2020/05/12/optimizing-date-algorithms.html + pub fn initUTC(year: i16, month: u8, day: u8, hour: u8, min: u8, sec: u8, micros: u32) !DateTime { + if (Date.valid(year, month, day) == false) { + return error.InvalidDate; + } + + if (Time.valid(hour, min, sec, micros) == false) { + return error.InvalidTime; + } + + const year_base = 4800; + const month_adj = @as(i32, @intCast(month)) - 3; // March-based month + const carry: u8 = if (month_adj < 0) 1 else 0; + const adjust: u8 = if (carry == 1) 12 else 0; + const year_adj: i64 = year + year_base - carry; + const month_days = @divTrunc(((month_adj + adjust) * 62719 + 769), 2048); + const leap_days = @divTrunc(year_adj, 4) - @divTrunc(year_adj, 100) + @divTrunc(year_adj, 400); + + const date_micros: i64 = (year_adj * 365 + leap_days + month_days + (day - 1) - 2472632) * MICROSECONDS_IN_A_DAY; + const time_micros = (@as(i64, @intCast(hour)) * MICROSECONDS_IN_AN_HOUR) + (@as(i64, @intCast(min)) * MICROSECONDS_IN_A_MIN) + (@as(i64, @intCast(sec)) * MICROSECONDS_IN_A_SEC) + micros; + + return fromUnix(date_micros + time_micros, .microseconds); + } + + pub fn fromUnix(value: i64, precision: TimestampPrecision) !DateTime { + switch (precision) { + .seconds => { + if (value < -210863520000 or value > 253402300799) { + return error.OutsideJulianPeriod; + } + return .{ .micros = value * 1_000_000 }; + }, + .milliseconds => { + if (value < -210863520000000 or value > 253402300799999) { + return error.OutsideJulianPeriod; + } + return .{ .micros = value * 1_000 }; + }, + .microseconds => { + if (value < -210863520000000000 or value > 253402300799999999) { + return error.OutsideJulianPeriod; + } + return .{ .micros = value }; + }, + } + } + + pub fn now() DateTime { + return .{ + .micros = std.time.microTimestamp(), + }; + } + + pub fn parse(input: []const u8, fmt: Format) !DateTime { + switch (fmt) { + .rfc822 => return parseRFC822(input), + .rfc3339 => return parseRFC3339(input), + } + } + + pub fn parseRFC822(input: []const u8) !DateTime { + if (input.len < 10) { + return error.InvalidDateTime; + } + var parser = Parser.init(input); + if (input[3] == ',' and input[4] == ' ') { + _ = std.meta.stringToEnum(enum { Mon, Tue, Wed, Thu, Fri, Sat, Sun }, input[0..3]) orelse return error.InvalidDate; + // skip over the "DoW, " + parser.pos = 5; + } + + const day = parser.paddedInt(u8, 2) orelse return error.InvalidDate; + if (parser.consumeIf(' ') == false) { + return error.InvalidDate; + } + + const month = std.meta.stringToEnum(enum { Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec }, parser.consumeN(3) orelse return error.InvalidDate) orelse return error.InvalidDate; + + if (parser.consumeIf(' ') == false) { + return error.InvalidDate; + } + + const year = parser.paddedInt(i16, 4) orelse blk: { + const short_year = parser.paddedInt(u8, 2) orelse return error.InvalidDate; + break :blk if (short_year > 68) 1900 + @as(i16, short_year) else 2000 + @as(i16, short_year); + }; + + if (parser.consumeIf(' ') == false) { + return error.InvalidDateTime; + } + const tm = try parser.time(false); + + if (parser.consumeIf(' ') == false) { + return error.InvalidTime; + } + + _ = std.meta.stringToEnum(enum { UT, GMT, Z }, parser.rest()) orelse return error.UnsupportedTimeZone; + + return initUTC(year, @intFromEnum(month) + 1, day, tm.hour, tm.min, tm.sec, tm.micros); + } + + pub fn parseRFC3339(input: []const u8) !DateTime { + var parser = Parser.init(input); + + const dt = try parser.rfc3339Date(); + + const year = dt.year; + if (year < -4712 or year > 9999) { + return error.OutsideJulianPeriod; + } + + // Per the spec, it can be argued thatt 't' and even ' ' should be allowed, + // but certainly not encouraged. + if (parser.consumeIf('T') == false) { + return error.InvalidDateTime; + } + + const tm = try parser.time(true); + + switch (parser.unconsumed()) { + 0 => return error.InvalidDateTime, + 1 => if (parser.consumeIf('Z') == false) { + return error.InvalidDateTime; + }, + 6 => { + const suffix = parser.rest(); + if (suffix[0] != '+' and suffix[0] != '-') { + return error.InvalidDateTime; + } + if (std.mem.eql(u8, suffix[1..], "00:00") == false) { + return error.NonUTCNotSupported; + } + }, + else => return error.InvalidDateTime, + } + + return initUTC(dt.year, dt.month, dt.day, tm.hour, tm.min, tm.sec, tm.micros); + } + + pub fn add(dt: DateTime, value: i64, unit: TimeUnit) !DateTime { + const micros = dt.micros; + switch (unit) { + .days => return fromUnix(micros + value * MICROSECONDS_IN_A_DAY, .microseconds), + .hours => return fromUnix(micros + value * MICROSECONDS_IN_AN_HOUR, .microseconds), + .minutes => return fromUnix(micros + value * MICROSECONDS_IN_A_MIN, .microseconds), + .seconds => return fromUnix(micros + value * MICROSECONDS_IN_A_SEC, .microseconds), + .milliseconds => return fromUnix(micros + value * 1_000, .microseconds), + .microseconds => return fromUnix(micros + value, .microseconds), + } + } + + pub fn sub(a: DateTime, b: DateTime, precision: TimestampPrecision) i64 { + return a.unix(precision) - b.unix(precision); + } + + // https://git.musl-libc.org/cgit/musl/tree/src/time/__secs_to_tm.c?h=v0.9.15 + pub fn date(dt: DateTime) Date { + // 2000-03-01 (mod 400 year, immediately after feb29 + const leap_epoch = 946684800 + 86400 * (31 + 29); + const days_per_400y = 365 * 400 + 97; + const days_per_100y = 365 * 100 + 24; + const days_per_4y = 365 * 4 + 1; + + // march-based + const month_days = [_]u8{ 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29 }; + + const secs = @divTrunc(dt.micros, 1_000_000) - leap_epoch; + + var days = @divTrunc(secs, 86400); + if (@rem(secs, 86400) < 0) { + days -= 1; + } + + var qc_cycles = @divTrunc(days, days_per_400y); + var rem_days = @rem(days, days_per_400y); + if (rem_days < 0) { + rem_days += days_per_400y; + qc_cycles -= 1; + } + + var c_cycles = @divTrunc(rem_days, days_per_100y); + if (c_cycles == 4) { + c_cycles -= 1; + } + rem_days -= c_cycles * days_per_100y; + + var q_cycles = @divTrunc(rem_days, days_per_4y); + if (q_cycles == 25) { + q_cycles -= 1; + } + rem_days -= q_cycles * days_per_4y; + + var rem_years = @divTrunc(rem_days, 365); + if (rem_years == 4) { + rem_years -= 1; + } + rem_days -= rem_years * 365; + + var year = rem_years + 4 * q_cycles + 100 * c_cycles + 400 * qc_cycles + 2000; + + var month: u8 = 0; + while (month_days[month] <= rem_days) : (month += 1) { + rem_days -= month_days[month]; + } + + month += 2; + if (month >= 12) { + year += 1; + month -= 12; + } + + return .{ + .year = @intCast(year), + .month = month + 1, + .day = @intCast(rem_days + 1), + }; + } + + pub fn time(dt: DateTime) Time { + const micros = @mod(dt.micros, MICROSECONDS_IN_A_DAY); + + return .{ + .hour = @intCast(@divTrunc(micros, MICROSECONDS_IN_AN_HOUR)), + .min = @intCast(@divTrunc(@rem(micros, MICROSECONDS_IN_AN_HOUR), MICROSECONDS_IN_A_MIN)), + .sec = @intCast(@divTrunc(@rem(micros, MICROSECONDS_IN_A_MIN), MICROSECONDS_IN_A_SEC)), + .micros = @intCast(@rem(micros, MICROSECONDS_IN_A_SEC)), + }; + } + + pub fn unix(self: DateTime, precision: TimestampPrecision) i64 { + const micros = self.micros; + return switch (precision) { + .seconds => @divTrunc(micros, 1_000_000), + .milliseconds => @divTrunc(micros, 1_000), + .microseconds => micros, + }; + } + + pub fn order(a: DateTime, b: DateTime) std.math.Order { + return std.math.order(a.micros, b.micros); + } + + pub fn format(self: DateTime, comptime _: []const u8, _: std.fmt.FormatOptions, out: anytype) !void { + var buf: [28]u8 = undefined; + const n = self.bufWrite(&buf); + try out.writeAll(buf[0..n]); + } + + pub fn jsonStringify(self: DateTime, out: anytype) !void { + var buf: [30]u8 = undefined; + buf[0] = '"'; + const n = self.bufWrite(buf[1..]); + buf[n + 1] = '"'; + try out.print("{s}", .{buf[0 .. n + 2]}); + } + + pub fn jsonParse(allocator: Allocator, source: anytype, options: anytype) !DateTime { + _ = options; + + switch (try source.nextAlloc(allocator, .alloc_if_needed)) { + inline .string, .allocated_string => |str| return parseRFC3339(str) catch return error.InvalidCharacter, + else => return error.UnexpectedToken, + } + } + + fn bufWrite(self: DateTime, buf: []u8) usize { + const date_n = writeDate(buf, self.date()); + + buf[date_n] = 'T'; + + const time_start = date_n + 1; + const time_n = writeTime(buf[time_start..], self.time()); + + const time_stop = time_start + time_n; + buf[time_stop] = 'Z'; + + return time_stop + 1; + } +}; + +fn writeDate(into: []u8, date: Date) u8 { + var buf: []u8 = undefined; + // cast year to a u16 so it doesn't insert a sign + // we don't want the + sign, ever + // and we don't even want it to insert the - sign, because it screws up + // the padding (we need to do it ourselfs) + const year = date.year; + if (year < 0) { + _ = std.fmt.formatIntBuf(into[1..], @as(u16, @intCast(year * -1)), 10, .lower, .{ .width = 4, .fill = '0' }); + into[0] = '-'; + buf = into[5..]; + } else { + _ = std.fmt.formatIntBuf(into, @as(u16, @intCast(year)), 10, .lower, .{ .width = 4, .fill = '0' }); + buf = into[4..]; + } + + buf[0] = '-'; + buf[1..3].* = paddingTwoDigits(date.month); + buf[3] = '-'; + buf[4..6].* = paddingTwoDigits(date.day); + + // return the length of the string. 10 for positive year, 11 for negative + return if (year < 0) 11 else 10; +} + +fn writeTime(into: []u8, time: Time) u8 { + into[0..2].* = paddingTwoDigits(time.hour); + into[2] = ':'; + into[3..5].* = paddingTwoDigits(time.min); + into[5] = ':'; + into[6..8].* = paddingTwoDigits(time.sec); + + const micros = time.micros; + if (micros == 0) { + return 8; + } + + if (@rem(micros, 1000) == 0) { + into[8] = '.'; + _ = std.fmt.formatIntBuf(into[9..12], micros / 1000, 10, .lower, .{ .width = 3, .fill = '0' }); + return 12; + } + + into[8] = '.'; + _ = std.fmt.formatIntBuf(into[9..15], micros, 10, .lower, .{ .width = 6, .fill = '0' }); + return 15; +} + +fn paddingTwoDigits(value: usize) [2]u8 { + std.debug.assert(value < 61); + const digits = "0001020304050607080910111213141516171819" ++ + "2021222324252627282930313233343536373839" ++ + "4041424344454647484950515253545556575859" ++ + "60"; + return digits[value * 2 ..][0..2].*; +} + +const Parser = struct { + input: []const u8, + pos: usize, + + fn init(input: []const u8) Parser { + return .{ + .pos = 0, + .input = input, + }; + } + + fn unconsumed(self: *const Parser) usize { + return self.input.len - self.pos; + } + + fn rest(self: *const Parser) []const u8 { + return self.input[self.pos..]; + } + + // unsafe, assumes caller has checked remaining first + fn peek(self: *const Parser) u8 { + return self.input[self.pos]; + } + + // unsafe, assumes caller has checked remaining first + fn consumeIf(self: *Parser, c: u8) bool { + const pos = self.pos; + if (self.input[pos] != c) { + return false; + } + self.pos = pos + 1; + return true; + } + + fn consumeN(self: *Parser, n: usize) ?[]const u8 { + const pos = self.pos; + const end = pos + n; + if (end > self.input.len) { + return null; + } + + defer self.pos = end; + return self.input[pos..end]; + } + + fn nanoseconds(self: *Parser) ?usize { + const start = self.pos; + const input = self.input[start..]; + + var len = input.len; + if (len == 0) { + return null; + } + + var value: usize = 0; + for (input, 0..) |b, i| { + const n = b -% '0'; // wrapping subtraction + if (n > 9) { + len = i; + break; + } + value = value * 10 + n; + } + + if (len > 9) { + return null; + } + + self.pos = start + len; + return value * std.math.pow(usize, 10, 9 - len); + } + + fn paddedInt(self: *Parser, comptime T: type, size: u8) ?T { + const pos = self.pos; + const end = pos + size; + const input = self.input; + + if (end > input.len) { + return null; + } + + var value: T = 0; + for (input[pos..end]) |b| { + const n = b -% '0'; // wrapping subtraction + if (n > 9) return null; + value = value * 10 + n; + } + self.pos = end; + return value; + } + + fn time(self: *Parser, allow_nano: bool) !Time { + const len = self.unconsumed(); + if (len < 5) { + return error.InvalidTime; + } + + const hour = self.paddedInt(u8, 2) orelse return error.InvalidTime; + if (self.consumeIf(':') == false) { + return error.InvalidTime; + } + + const min = self.paddedInt(u8, 2) orelse return error.InvalidTime; + if (len == 5 or self.consumeIf(':') == false) { + return Time.init(hour, min, 0, 0); + } + + const sec = self.paddedInt(u8, 2) orelse return error.InvalidTime; + if (allow_nano == false or len == 8 or self.consumeIf('.') == false) { + return Time.init(hour, min, sec, 0); + } + + const nanos = self.nanoseconds() orelse return error.InvalidTime; + return Time.init(hour, min, sec, @intCast(nanos / 1000)); + } + + fn iso8601Date(self: *Parser) !Date { + const len = self.unconsumed(); + if (len < 8) { + return error.InvalidDate; + } + + const negative = self.consumeIf('-'); + const year = self.paddedInt(i16, 4) orelse return error.InvalidDate; + + var with_dashes = false; + if (self.consumeIf('-')) { + if (len < 10) { + return error.InvalidDate; + } + with_dashes = true; + } + + const month = self.paddedInt(u8, 2) orelse return error.InvalidDate; + if (self.consumeIf('-') == !with_dashes) { + return error.InvalidDate; + } + + const day = self.paddedInt(u8, 2) orelse return error.InvalidDate; + return Date.init(if (negative) -year else year, month, day); + } + + fn rfc3339Date(self: *Parser) !Date { + const len = self.unconsumed(); + if (len < 10) { + return error.InvalidDate; + } + + const negative = self.consumeIf('-'); + const year = self.paddedInt(i16, 4) orelse return error.InvalidDate; + + if (self.consumeIf('-') == false) { + return error.InvalidDate; + } + + const month = self.paddedInt(u8, 2) orelse return error.InvalidDate; + + if (self.consumeIf('-') == false) { + return error.InvalidDate; + } + + const day = self.paddedInt(u8, 2) orelse return error.InvalidDate; + return Date.init(if (negative) -year else year, month, day); + } +}; + +const testing = @import("testing.zig"); +test "Date: json" { + { + // date, positive year + const date = Date{ .year = 2023, .month = 9, .day = 22 }; + const out = try std.json.stringifyAlloc(testing.allocator, date, .{}); + defer testing.allocator.free(out); + try testing.expectString("\"2023-09-22\"", out); + } + + { + // date, negative year + const date = Date{ .year = -4, .month = 12, .day = 3 }; + const out = try std.json.stringifyAlloc(testing.allocator, date, .{}); + defer testing.allocator.free(out); + try testing.expectString("\"-0004-12-03\"", out); + } + + { + // parse + const ts = try std.json.parseFromSlice(TestStruct, testing.allocator, "{\"date\":\"2023-09-22\"}", .{}); + defer ts.deinit(); + try testing.expectEqual(Date{ .year = 2023, .month = 9, .day = 22 }, ts.value.date.?); + } +} + +test "Date: format" { + { + var buf: [20]u8 = undefined; + const out = try std.fmt.bufPrint(&buf, "{s}", .{Date{ .year = 2023, .month = 5, .day = 22 }}); + try testing.expectString("2023-05-22", out); + } + + { + var buf: [20]u8 = undefined; + const out = try std.fmt.bufPrint(&buf, "{s}", .{Date{ .year = -102, .month = 12, .day = 9 }}); + try testing.expectString("-0102-12-09", out); + } +} + +test "Date: parse ISO8601" { + { + //valid YYYY-MM-DD + try testing.expectEqual(Date{ .year = 2023, .month = 5, .day = 22 }, try Date.parse("2023-05-22", .iso8601)); + try testing.expectEqual(Date{ .year = -2023, .month = 2, .day = 3 }, try Date.parse("-2023-02-03", .iso8601)); + try testing.expectEqual(Date{ .year = 1, .month = 2, .day = 3 }, try Date.parse("0001-02-03", .iso8601)); + try testing.expectEqual(Date{ .year = -1, .month = 2, .day = 3 }, try Date.parse("-0001-02-03", .iso8601)); + } + + { + //valid YYYYMMDD + try testing.expectEqual(Date{ .year = 2023, .month = 5, .day = 22 }, try Date.parse("20230522", .iso8601)); + try testing.expectEqual(Date{ .year = -2023, .month = 2, .day = 3 }, try Date.parse("-20230203", .iso8601)); + try testing.expectEqual(Date{ .year = 1, .month = 2, .day = 3 }, try Date.parse("00010203", .iso8601)); + try testing.expectEqual(Date{ .year = -1, .month = 2, .day = 3 }, try Date.parse("-00010203", .iso8601)); + } +} + +test "Date: parse RFC339" { + { + //valid YYYY-MM-DD + try testing.expectEqual(Date{ .year = 2023, .month = 5, .day = 22 }, try Date.parse("2023-05-22", .rfc3339)); + try testing.expectEqual(Date{ .year = -2023, .month = 2, .day = 3 }, try Date.parse("-2023-02-03", .rfc3339)); + try testing.expectEqual(Date{ .year = 1, .month = 2, .day = 3 }, try Date.parse("0001-02-03", .rfc3339)); + try testing.expectEqual(Date{ .year = -1, .month = 2, .day = 3 }, try Date.parse("-0001-02-03", .rfc3339)); + } + + { + //valid YYYYMMDD + try testing.expectError(error.InvalidDate, Date.parse("20230522", .rfc3339)); + try testing.expectError(error.InvalidDate, Date.parse("-20230203", .rfc3339)); + try testing.expectError(error.InvalidDate, Date.parse("00010203", .rfc3339)); + try testing.expectError(error.InvalidDate, Date.parse("-00010203", .rfc3339)); + } +} + +test "Date: parse invalid common" { + for (&[_]Date.Format{ .rfc3339, .iso8601 }) |format| { + { + // invalid format + try testing.expectError(error.InvalidDate, Date.parse("", format)); + try testing.expectError(error.InvalidDate, Date.parse("2023/01-02", format)); + try testing.expectError(error.InvalidDate, Date.parse("2023-01/02", format)); + try testing.expectError(error.InvalidDate, Date.parse("0001-01-01 ", format)); + try testing.expectError(error.InvalidDate, Date.parse("2023-1-02", format)); + try testing.expectError(error.InvalidDate, Date.parse("2023-01-2", format)); + try testing.expectError(error.InvalidDate, Date.parse("9-01-2", format)); + try testing.expectError(error.InvalidDate, Date.parse("99-01-2", format)); + try testing.expectError(error.InvalidDate, Date.parse("999-01-2", format)); + try testing.expectError(error.InvalidDate, Date.parse("-999-01-2", format)); + try testing.expectError(error.InvalidDate, Date.parse("-1-01-2", format)); + } + + { + // invalid month + try testing.expectError(error.InvalidDate, Date.parse("2023-00-22", format)); + try testing.expectError(error.InvalidDate, Date.parse("2023-0A-22", format)); + try testing.expectError(error.InvalidDate, Date.parse("2023-13-22", format)); + try testing.expectError(error.InvalidDate, Date.parse("2023-99-22", format)); + try testing.expectError(error.InvalidDate, Date.parse("-2023-00-22", format)); + try testing.expectError(error.InvalidDate, Date.parse("-2023-13-22", format)); + try testing.expectError(error.InvalidDate, Date.parse("-2023-99-22", format)); + } + + { + // invalid day + try testing.expectError(error.InvalidDate, Date.parse("2023-01-00", format)); + try testing.expectError(error.InvalidDate, Date.parse("2023-01-32", format)); + try testing.expectError(error.InvalidDate, Date.parse("2023-02-29", format)); + try testing.expectError(error.InvalidDate, Date.parse("2023-03-32", format)); + try testing.expectError(error.InvalidDate, Date.parse("2023-04-31", format)); + try testing.expectError(error.InvalidDate, Date.parse("2023-05-32", format)); + try testing.expectError(error.InvalidDate, Date.parse("2023-06-31", format)); + try testing.expectError(error.InvalidDate, Date.parse("2023-07-32", format)); + try testing.expectError(error.InvalidDate, Date.parse("2023-08-32", format)); + try testing.expectError(error.InvalidDate, Date.parse("2023-09-31", format)); + try testing.expectError(error.InvalidDate, Date.parse("2023-10-32", format)); + try testing.expectError(error.InvalidDate, Date.parse("2023-11-31", format)); + try testing.expectError(error.InvalidDate, Date.parse("2023-12-32", format)); + } + + { + // valid (max day) + try testing.expectEqual(Date{ .year = 2023, .month = 1, .day = 31 }, try Date.parse("2023-01-31", format)); + try testing.expectEqual(Date{ .year = 2023, .month = 2, .day = 28 }, try Date.parse("2023-02-28", format)); + try testing.expectEqual(Date{ .year = 2023, .month = 3, .day = 31 }, try Date.parse("2023-03-31", format)); + try testing.expectEqual(Date{ .year = 2023, .month = 4, .day = 30 }, try Date.parse("2023-04-30", format)); + try testing.expectEqual(Date{ .year = 2023, .month = 5, .day = 31 }, try Date.parse("2023-05-31", format)); + try testing.expectEqual(Date{ .year = 2023, .month = 6, .day = 30 }, try Date.parse("2023-06-30", format)); + try testing.expectEqual(Date{ .year = 2023, .month = 7, .day = 31 }, try Date.parse("2023-07-31", format)); + try testing.expectEqual(Date{ .year = 2023, .month = 8, .day = 31 }, try Date.parse("2023-08-31", format)); + try testing.expectEqual(Date{ .year = 2023, .month = 9, .day = 30 }, try Date.parse("2023-09-30", format)); + try testing.expectEqual(Date{ .year = 2023, .month = 10, .day = 31 }, try Date.parse("2023-10-31", format)); + try testing.expectEqual(Date{ .year = 2023, .month = 11, .day = 30 }, try Date.parse("2023-11-30", format)); + try testing.expectEqual(Date{ .year = 2023, .month = 12, .day = 31 }, try Date.parse("2023-12-31", format)); + } + + { + // leap years + try testing.expectEqual(Date{ .year = 2000, .month = 2, .day = 29 }, try Date.parse("2000-02-29", format)); + try testing.expectEqual(Date{ .year = 2400, .month = 2, .day = 29 }, try Date.parse("2400-02-29", format)); + try testing.expectEqual(Date{ .year = 2012, .month = 2, .day = 29 }, try Date.parse("2012-02-29", format)); + try testing.expectEqual(Date{ .year = 2024, .month = 2, .day = 29 }, try Date.parse("2024-02-29", format)); + + try testing.expectError(error.InvalidDate, Date.parse("2000-02-30", format)); + try testing.expectError(error.InvalidDate, Date.parse("2400-02-30", format)); + try testing.expectError(error.InvalidDate, Date.parse("2012-02-30", format)); + try testing.expectError(error.InvalidDate, Date.parse("2024-02-30", format)); + + try testing.expectError(error.InvalidDate, Date.parse("2100-02-29", format)); + try testing.expectError(error.InvalidDate, Date.parse("2200-02-29", format)); + } + } +} + +test "Date: order" { + { + const a = Date{ .year = 2023, .month = 5, .day = 22 }; + const b = Date{ .year = 2023, .month = 5, .day = 22 }; + try testing.expectEqual(std.math.Order.eq, a.order(b)); + } + + { + const a = Date{ .year = 2023, .month = 5, .day = 22 }; + const b = Date{ .year = 2022, .month = 5, .day = 22 }; + try testing.expectEqual(std.math.Order.gt, a.order(b)); + try testing.expectEqual(std.math.Order.lt, b.order(a)); + } + + { + const a = Date{ .year = 2022, .month = 6, .day = 22 }; + const b = Date{ .year = 2022, .month = 5, .day = 22 }; + try testing.expectEqual(std.math.Order.gt, a.order(b)); + try testing.expectEqual(std.math.Order.lt, b.order(a)); + } + + { + const a = Date{ .year = 2023, .month = 5, .day = 23 }; + const b = Date{ .year = 2022, .month = 5, .day = 22 }; + try testing.expectEqual(std.math.Order.gt, a.order(b)); + try testing.expectEqual(std.math.Order.lt, b.order(a)); + } +} + +test "Time: json" { + { + // time no fraction + const time = Time{ .hour = 23, .min = 59, .sec = 2, .micros = 0 }; + const out = try std.json.stringifyAlloc(testing.allocator, time, .{}); + defer testing.allocator.free(out); + try testing.expectString("\"23:59:02\"", out); + } + + { + // time, milliseconds only + const time = Time{ .hour = 7, .min = 9, .sec = 32, .micros = 202000 }; + const out = try std.json.stringifyAlloc(testing.allocator, time, .{}); + defer testing.allocator.free(out); + try testing.expectString("\"07:09:32.202\"", out); + } + + { + // time, micros + const time = Time{ .hour = 1, .min = 2, .sec = 3, .micros = 123456 }; + const out = try std.json.stringifyAlloc(testing.allocator, time, .{}); + defer testing.allocator.free(out); + try testing.expectString("\"01:02:03.123456\"", out); + } + + { + // parse + const ts = try std.json.parseFromSlice(TestStruct, testing.allocator, "{\"time\":\"01:02:03.123456\"}", .{}); + defer ts.deinit(); + try testing.expectEqual(Time{ .hour = 1, .min = 2, .sec = 3, .micros = 123456 }, ts.value.time.?); + } +} + +test "Time: format" { + { + var buf: [20]u8 = undefined; + const out = try std.fmt.bufPrint(&buf, "{s}", .{Time{ .hour = 23, .min = 59, .sec = 59, .micros = 0 }}); + try testing.expectString("23:59:59", out); + } + + { + var buf: [20]u8 = undefined; + const out = try std.fmt.bufPrint(&buf, "{s}", .{Time{ .hour = 8, .min = 9, .sec = 10, .micros = 12 }}); + try testing.expectString("08:09:10.000012", out); + } + + { + var buf: [20]u8 = undefined; + const out = try std.fmt.bufPrint(&buf, "{s}", .{Time{ .hour = 8, .min = 9, .sec = 10, .micros = 123 }}); + try testing.expectString("08:09:10.000123", out); + } + + { + var buf: [20]u8 = undefined; + const out = try std.fmt.bufPrint(&buf, "{s}", .{Time{ .hour = 8, .min = 9, .sec = 10, .micros = 1234 }}); + try testing.expectString("08:09:10.001234", out); + } + + { + var buf: [20]u8 = undefined; + const out = try std.fmt.bufPrint(&buf, "{s}", .{Time{ .hour = 8, .min = 9, .sec = 10, .micros = 12345 }}); + try testing.expectString("08:09:10.012345", out); + } + + { + var buf: [20]u8 = undefined; + const out = try std.fmt.bufPrint(&buf, "{s}", .{Time{ .hour = 8, .min = 9, .sec = 10, .micros = 123456 }}); + try testing.expectString("08:09:10.123456", out); + } +} + +test "Time: parse" { + { + //valid + try testing.expectEqual(Time{ .hour = 9, .min = 8, .sec = 0, .micros = 0 }, try Time.parse("09:08", .rfc3339)); + try testing.expectEqual(Time{ .hour = 9, .min = 8, .sec = 5, .micros = 123000 }, try Time.parse("09:08:05.123", .rfc3339)); + try testing.expectEqual(Time{ .hour = 23, .min = 59, .sec = 59, .micros = 0 }, try Time.parse("23:59:59", .rfc3339)); + try testing.expectEqual(Time{ .hour = 0, .min = 0, .sec = 0, .micros = 0 }, try Time.parse("00:00:00", .rfc3339)); + try testing.expectEqual(Time{ .hour = 0, .min = 0, .sec = 0, .micros = 0 }, try Time.parse("00:00:00.0", .rfc3339)); + try testing.expectEqual(Time{ .hour = 0, .min = 0, .sec = 0, .micros = 1 }, try Time.parse("00:00:00.000001", .rfc3339)); + try testing.expectEqual(Time{ .hour = 0, .min = 0, .sec = 0, .micros = 12 }, try Time.parse("00:00:00.000012", .rfc3339)); + try testing.expectEqual(Time{ .hour = 0, .min = 0, .sec = 0, .micros = 123 }, try Time.parse("00:00:00.000123", .rfc3339)); + try testing.expectEqual(Time{ .hour = 0, .min = 0, .sec = 0, .micros = 1234 }, try Time.parse("00:00:00.001234", .rfc3339)); + try testing.expectEqual(Time{ .hour = 0, .min = 0, .sec = 0, .micros = 12345 }, try Time.parse("00:00:00.012345", .rfc3339)); + try testing.expectEqual(Time{ .hour = 0, .min = 0, .sec = 0, .micros = 123456 }, try Time.parse("00:00:00.123456", .rfc3339)); + try testing.expectEqual(Time{ .hour = 0, .min = 0, .sec = 0, .micros = 123456 }, try Time.parse("00:00:00.1234567", .rfc3339)); + try testing.expectEqual(Time{ .hour = 0, .min = 0, .sec = 0, .micros = 123456 }, try Time.parse("00:00:00.12345678", .rfc3339)); + try testing.expectEqual(Time{ .hour = 0, .min = 0, .sec = 0, .micros = 123456 }, try Time.parse("00:00:00.123456789", .rfc3339)); + } + + { + try testing.expectError(error.InvalidTime, Time.parse("", .rfc3339)); + try testing.expectError(error.InvalidTime, Time.parse("01:00:", .rfc3339)); + try testing.expectError(error.InvalidTime, Time.parse("1:00:00", .rfc3339)); + try testing.expectError(error.InvalidTime, Time.parse("10:1:00", .rfc3339)); + try testing.expectError(error.InvalidTime, Time.parse("10:11:4", .rfc3339)); + try testing.expectError(error.InvalidTime, Time.parse("10:20:30.", .rfc3339)); + try testing.expectError(error.InvalidTime, Time.parse("10:20:30.a", .rfc3339)); + try testing.expectError(error.InvalidTime, Time.parse("10:20:30.1234567899", .rfc3339)); + try testing.expectError(error.InvalidTime, Time.parse("10:20:30.123Z", .rfc3339)); + try testing.expectError(error.InvalidTime, Time.parse("24:00:00", .rfc3339)); + try testing.expectError(error.InvalidTime, Time.parse("00:60:00", .rfc3339)); + try testing.expectError(error.InvalidTime, Time.parse("00:00:60", .rfc3339)); + try testing.expectError(error.InvalidTime, Time.parse("0a:00:00", .rfc3339)); + try testing.expectError(error.InvalidTime, Time.parse("00:0a:00", .rfc3339)); + try testing.expectError(error.InvalidTime, Time.parse("00:00:0a", .rfc3339)); + try testing.expectError(error.InvalidTime, Time.parse("00/00:00", .rfc3339)); + try testing.expectError(error.InvalidTime, Time.parse("00:00 00", .rfc3339)); + } +} + +test "Time: order" { + { + const a = Time{ .hour = 19, .min = 17, .sec = 22, .micros = 101002 }; + const b = Time{ .hour = 19, .min = 17, .sec = 22, .micros = 101002 }; + try testing.expectEqual(std.math.Order.eq, a.order(b)); + } + + { + const a = Time{ .hour = 20, .min = 17, .sec = 22, .micros = 101002 }; + const b = Time{ .hour = 19, .min = 17, .sec = 22, .micros = 101002 }; + try testing.expectEqual(std.math.Order.gt, a.order(b)); + try testing.expectEqual(std.math.Order.lt, b.order(a)); + } + + { + const a = Time{ .hour = 19, .min = 18, .sec = 22, .micros = 101002 }; + const b = Time{ .hour = 19, .min = 17, .sec = 22, .micros = 101002 }; + try testing.expectEqual(std.math.Order.gt, a.order(b)); + try testing.expectEqual(std.math.Order.lt, b.order(a)); + } + + { + const a = Time{ .hour = 19, .min = 17, .sec = 23, .micros = 101002 }; + const b = Time{ .hour = 19, .min = 17, .sec = 22, .micros = 101002 }; + try testing.expectEqual(std.math.Order.gt, a.order(b)); + try testing.expectEqual(std.math.Order.lt, b.order(a)); + } + + { + const a = Time{ .hour = 19, .min = 17, .sec = 22, .micros = 101003 }; + const b = Time{ .hour = 19, .min = 17, .sec = 22, .micros = 101002 }; + try testing.expectEqual(std.math.Order.gt, a.order(b)); + try testing.expectEqual(std.math.Order.lt, b.order(a)); + } +} + +test "DateTime: initUTC" { + // GO + // for i := 0; i < 100; i++ { + // us := rand.Int63n(31536000000000000) + // if i%2 == 1 { + // us = -us + // } + // date := time.UnixMicro(us).UTC() + // fmt.Printf("\ttry testing.expectEqual(%d, (try DateTime.initUTC(%d, %d, %d, %d, %d, %d, %d)).micros);\n", us, date.Year(), date.Month(), date.Day(), date.Hour(), date.Minute(), date.Second(), date.Nanosecond()/1000) + // } + try testing.expectEqual(31185488490276150, (try DateTime.initUTC(2958, 3, 25, 3, 41, 30, 276150)).micros); + try testing.expectEqual(-17564653328342207, (try DateTime.initUTC(1413, 5, 26, 9, 37, 51, 657793)).micros); + try testing.expectEqual(11204762425459393, (try DateTime.initUTC(2325, 1, 24, 18, 0, 25, 459393)).micros); + try testing.expectEqual(-11416605162739875, (try DateTime.initUTC(1608, 3, 22, 8, 47, 17, 260125)).micros); + try testing.expectEqual(4075732367920414, (try DateTime.initUTC(2099, 2, 25, 19, 52, 47, 920414)).micros); + try testing.expectEqual(-18408335598163579, (try DateTime.initUTC(1386, 8, 30, 13, 26, 41, 836421)).micros); + try testing.expectEqual(17086490946271926, (try DateTime.initUTC(2511, 6, 14, 7, 29, 6, 271926)).micros); + try testing.expectEqual(-235277150936616, (try DateTime.initUTC(1962, 7, 18, 21, 14, 9, 63384)).micros); + try testing.expectEqual(11104788804726682, (try DateTime.initUTC(2321, 11, 24, 15, 33, 24, 726682)).micros); + try testing.expectEqual(-4568937205156452, (try DateTime.initUTC(1825, 3, 20, 18, 46, 34, 843548)).micros); + try testing.expectEqual(24765673968274275, (try DateTime.initUTC(2754, 10, 17, 17, 52, 48, 274275)).micros); + try testing.expectEqual(-7121990846251510, (try DateTime.initUTC(1744, 4, 24, 13, 12, 33, 748490)).micros); + try testing.expectEqual(17226397205968456, (try DateTime.initUTC(2515, 11, 19, 14, 20, 5, 968456)).micros); + try testing.expectEqual(-6754262392339050, (try DateTime.initUTC(1755, 12, 19, 16, 0, 7, 660950)).micros); + try testing.expectEqual(16357572620714009, (try DateTime.initUTC(2488, 5, 7, 18, 10, 20, 714009)).micros); + try testing.expectEqual(-25688820176639049, (try DateTime.initUTC(1155, 12, 15, 16, 37, 3, 360951)).micros); + try testing.expectEqual(20334458172336139, (try DateTime.initUTC(2614, 5, 17, 12, 36, 12, 336139)).micros); + try testing.expectEqual(-30602962159178117, (try DateTime.initUTC(1000, 3, 26, 1, 10, 40, 821883)).micros); + try testing.expectEqual(10851036879825648, (try DateTime.initUTC(2313, 11, 9, 16, 54, 39, 825648)).micros); + try testing.expectEqual(-21853769826060317, (try DateTime.initUTC(1277, 6, 24, 20, 22, 53, 939683)).micros); + try testing.expectEqual(23747326217087461, (try DateTime.initUTC(2722, 7, 11, 7, 30, 17, 87461)).micros); + try testing.expectEqual(-6579703114708064, (try DateTime.initUTC(1761, 7, 1, 0, 41, 25, 291936)).micros); + try testing.expectEqual(14734931422924073, (try DateTime.initUTC(2436, 12, 6, 4, 30, 22, 924073)).micros); + try testing.expectEqual(-14370161672281011, (try DateTime.initUTC(1514, 8, 18, 16, 25, 27, 718989)).micros); + try testing.expectEqual(21611484560584058, (try DateTime.initUTC(2654, 11, 3, 22, 9, 20, 584058)).micros); + try testing.expectEqual(-15774514890527755, (try DateTime.initUTC(1470, 2, 15, 14, 18, 29, 472245)).micros); + try testing.expectEqual(12457884381373706, (try DateTime.initUTC(2364, 10, 10, 11, 26, 21, 373706)).micros); + try testing.expectEqual(-9291409512875127, (try DateTime.initUTC(1675, 7, 26, 12, 54, 47, 124873)).micros); + try testing.expectEqual(18766703512694310, (try DateTime.initUTC(2564, 9, 10, 5, 11, 52, 694310)).micros); + try testing.expectEqual(-10898338457124469, (try DateTime.initUTC(1624, 8, 23, 19, 45, 42, 875531)).micros); + try testing.expectEqual(27404278841361952, (try DateTime.initUTC(2838, 5, 29, 3, 40, 41, 361952)).micros); + try testing.expectEqual(-11493696741549109, (try DateTime.initUTC(1605, 10, 12, 2, 27, 38, 450891)).micros); + try testing.expectEqual(25167839321247044, (try DateTime.initUTC(2767, 7, 16, 10, 28, 41, 247044)).micros); + try testing.expectEqual(-8645720427930599, (try DateTime.initUTC(1696, 1, 10, 18, 59, 32, 69401)).micros); + try testing.expectEqual(7021225980669527, (try DateTime.initUTC(2192, 6, 29, 4, 33, 0, 669527)).micros); + try testing.expectEqual(-22567421500525473, (try DateTime.initUTC(1254, 11, 12, 23, 48, 19, 474527)).micros); + try testing.expectEqual(3592419409525180, (try DateTime.initUTC(2083, 11, 2, 22, 16, 49, 525180)).micros); + try testing.expectEqual(-24897829995733878, (try DateTime.initUTC(1181, 1, 7, 16, 6, 44, 266122)).micros); + try testing.expectEqual(1801796752202729, (try DateTime.initUTC(2027, 2, 5, 3, 5, 52, 202729)).micros); + try testing.expectEqual(-21458729756349585, (try DateTime.initUTC(1289, 12, 31, 1, 44, 3, 650415)).micros); + try testing.expectEqual(27431277767015263, (try DateTime.initUTC(2839, 4, 6, 15, 22, 47, 15263)).micros); + try testing.expectEqual(-11932647633976328, (try DateTime.initUTC(1591, 11, 14, 15, 39, 26, 23672)).micros); + try testing.expectEqual(11561116817530249, (try DateTime.initUTC(2336, 5, 11, 5, 20, 17, 530249)).micros); + try testing.expectEqual(-20238374988448844, (try DateTime.initUTC(1328, 9, 2, 13, 10, 11, 551156)).micros); + try testing.expectEqual(17825448287939368, (try DateTime.initUTC(2534, 11, 13, 1, 24, 47, 939368)).micros); + try testing.expectEqual(-16551182110752962, (try DateTime.initUTC(1445, 7, 7, 9, 24, 49, 247038)).micros); + try testing.expectEqual(7773488831126355, (try DateTime.initUTC(2216, 5, 1, 22, 27, 11, 126355)).micros); + try testing.expectEqual(-17967725644400042, (try DateTime.initUTC(1400, 8, 17, 5, 5, 55, 599958)).micros); + try testing.expectEqual(30634276344447791, (try DateTime.initUTC(2940, 10, 5, 9, 12, 24, 447791)).micros); + try testing.expectEqual(-3201531339091604, (try DateTime.initUTC(1868, 7, 19, 5, 44, 20, 908396)).micros); + try testing.expectEqual(16621702451341054, (try DateTime.initUTC(2496, 9, 19, 19, 34, 11, 341054)).micros); + try testing.expectEqual(-12321145808433043, (try DateTime.initUTC(1579, 7, 24, 3, 29, 51, 566957)).micros); + try testing.expectEqual(116851935152341, (try DateTime.initUTC(1973, 9, 14, 10, 52, 15, 152341)).micros); + try testing.expectEqual(-26516365395395707, (try DateTime.initUTC(1129, 9, 24, 14, 56, 44, 604293)).micros); + try testing.expectEqual(29944637164250909, (try DateTime.initUTC(2918, 11, 28, 10, 46, 4, 250909)).micros); + try testing.expectEqual(-14268089958574835, (try DateTime.initUTC(1517, 11, 12, 1, 40, 41, 425165)).micros); + try testing.expectEqual(10902808879115327, (try DateTime.initUTC(2315, 7, 1, 22, 1, 19, 115327)).micros); + try testing.expectEqual(-13675746347719473, (try DateTime.initUTC(1536, 8, 19, 21, 34, 12, 280527)).micros); + try testing.expectEqual(9823904882276154, (try DateTime.initUTC(2281, 4, 22, 14, 28, 2, 276154)).micros); + try testing.expectEqual(-8027825490751946, (try DateTime.initUTC(1715, 8, 11, 8, 28, 29, 248054)).micros); + try testing.expectEqual(8338818189787922, (try DateTime.initUTC(2234, 4, 1, 2, 23, 9, 787922)).micros); + try testing.expectEqual(-2417779710874201, (try DateTime.initUTC(1893, 5, 20, 10, 31, 29, 125799)).micros); + try testing.expectEqual(15579463520321126, (try DateTime.initUTC(2463, 9, 10, 20, 45, 20, 321126)).micros); + try testing.expectEqual(-30111774746323219, (try DateTime.initUTC(1015, 10, 19, 2, 7, 33, 676781)).micros); + try testing.expectEqual(8586318907201828, (try DateTime.initUTC(2242, 2, 2, 16, 35, 7, 201828)).micros); + try testing.expectEqual(-20727462914538728, (try DateTime.initUTC(1313, 3, 4, 19, 24, 45, 461272)).micros); + try testing.expectEqual(12684924982677857, (try DateTime.initUTC(2371, 12, 21, 6, 16, 22, 677857)).micros); + try testing.expectEqual(-26995363453933698, (try DateTime.initUTC(1114, 7, 21, 15, 55, 46, 66302)).micros); + try testing.expectEqual(5769549719315448, (try DateTime.initUTC(2152, 10, 30, 4, 41, 59, 315448)).micros); + try testing.expectEqual(-9362762735064704, (try DateTime.initUTC(1673, 4, 21, 16, 34, 24, 935296)).micros); + try testing.expectEqual(5196087673076825, (try DateTime.initUTC(2134, 8, 28, 21, 41, 13, 76825)).micros); + try testing.expectEqual(-10198286600499296, (try DateTime.initUTC(1646, 10, 30, 6, 36, 39, 500704)).micros); + try testing.expectEqual(19333137979539125, (try DateTime.initUTC(2582, 8, 23, 4, 6, 19, 539125)).micros); + try testing.expectEqual(-18867539824804327, (try DateTime.initUTC(1372, 2, 10, 16, 42, 55, 195673)).micros); + try testing.expectEqual(14853031249581056, (try DateTime.initUTC(2440, 9, 3, 2, 0, 49, 581056)).micros); + try testing.expectEqual(-1356282109230506, (try DateTime.initUTC(1927, 1, 9, 6, 58, 10, 769494)).micros); + try testing.expectEqual(15713222018105813, (try DateTime.initUTC(2467, 12, 6, 23, 53, 38, 105813)).micros); + try testing.expectEqual(-12693041975378709, (try DateTime.initUTC(1567, 10, 10, 19, 0, 24, 621291)).micros); + try testing.expectEqual(29394313298789588, (try DateTime.initUTC(2901, 6, 20, 23, 1, 38, 789588)).micros); + try testing.expectEqual(-10583952098364782, (try DateTime.initUTC(1634, 8, 10, 13, 18, 21, 635218)).micros); + try testing.expectEqual(22418800474726154, (try DateTime.initUTC(2680, 6, 3, 20, 34, 34, 726154)).micros); + try testing.expectEqual(-13067278028607441, (try DateTime.initUTC(1555, 12, 1, 8, 32, 51, 392559)).micros); + try testing.expectEqual(22348003126725817, (try DateTime.initUTC(2678, 3, 7, 10, 38, 46, 725817)).micros); + try testing.expectEqual(-11101998054915852, (try DateTime.initUTC(1618, 3, 11, 15, 39, 5, 84148)).micros); + try testing.expectEqual(30004645932503986, (try DateTime.initUTC(2920, 10, 22, 23, 52, 12, 503986)).micros); + try testing.expectEqual(-27551013013624622, (try DateTime.initUTC(1096, 12, 10, 12, 49, 46, 375378)).micros); + try testing.expectEqual(10162791607756167, (try DateTime.initUTC(2292, 1, 17, 21, 40, 7, 756167)).micros); + try testing.expectEqual(-31309636417799549, (try DateTime.initUTC(977, 11, 1, 22, 46, 22, 200451)).micros); + try testing.expectEqual(9816298180956872, (try DateTime.initUTC(2281, 1, 24, 13, 29, 40, 956872)).micros); + try testing.expectEqual(-13248552913008079, (try DateTime.initUTC(1550, 3, 4, 6, 24, 46, 991921)).micros); + try testing.expectEqual(24898184818866845, (try DateTime.initUTC(2758, 12, 29, 10, 26, 58, 866845)).micros); + try testing.expectEqual(-10721424878768860, (try DateTime.initUTC(1630, 4, 2, 10, 25, 21, 231140)).micros); + try testing.expectEqual(3556757075942051, (try DateTime.initUTC(2082, 9, 16, 4, 4, 35, 942051)).micros); + try testing.expectEqual(-9515936853544912, (try DateTime.initUTC(1668, 6, 13, 20, 12, 26, 455088)).micros); + try testing.expectEqual(23236928933459964, (try DateTime.initUTC(2706, 5, 8, 22, 28, 53, 459964)).micros); + try testing.expectEqual(-5811784886171477, (try DateTime.initUTC(1785, 10, 30, 23, 18, 33, 828523)).micros); + try testing.expectEqual(27342496921109542, (try DateTime.initUTC(2836, 6, 13, 2, 2, 1, 109542)).micros); + try testing.expectEqual(-25369943235288340, (try DateTime.initUTC(1166, 1, 22, 9, 32, 44, 711660)).micros); + try testing.expectEqual(10054378230055484, (try DateTime.initUTC(2288, 8, 11, 2, 50, 30, 55484)).micros); + try testing.expectEqual(-10826899878642792, (try DateTime.initUTC(1626, 11, 28, 15, 48, 41, 357208)).micros); +} + +test "DateTime: now" { + const dt = DateTime.now(); + try testing.expectDelta(std.time.microTimestamp(), dt.micros, 1000); +} + +test "DateTime: date" { + try testing.expectEqual(Date{ .year = 2023, .month = 11, .day = 25 }, (try DateTime.fromUnix(1700886257, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2023, .month = 11, .day = 25 }, (try DateTime.fromUnix(1700886257655, .milliseconds)).date()); + try testing.expectEqual(Date{ .year = 2023, .month = 11, .day = 25 }, (try DateTime.fromUnix(1700886257655392, .microseconds)).date()); + try testing.expectEqual(Date{ .year = 1970, .month = 1, .day = 1 }, (try DateTime.fromUnix(0, .milliseconds)).date()); + + // GO: + // for i := 0; i < 100; i++ { + // us := rand.Int63n(31536000000000000) + // if i%2 == 1 { + // us = -us + // } + // date := time.UnixMicro(us).UTC() + // fmt.Printf("\ttry testing.expectEqual(Date{.year = %d, .month = %d, .day = %d}, DateTime.fromUnix(%d, .seconds).date());\n", date.Year(), date.Month(), date.Day(), date.Unix()) + // } + try testing.expectEqual(Date{ .year = 2438, .month = 8, .day = 8 }, (try DateTime.fromUnix(14787635606, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1290, .month = 10, .day = 9 }, (try DateTime.fromUnix(-21434368940, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2769, .month = 12, .day = 3 }, (try DateTime.fromUnix(25243136028, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1437, .month = 6, .day = 30 }, (try DateTime.fromUnix(-16804239664, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2752, .month = 4, .day = 7 }, (try DateTime.fromUnix(24685876670, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1484, .month = 1, .day = 29 }, (try DateTime.fromUnix(-15334209737, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2300, .month = 1, .day = 4 }, (try DateTime.fromUnix(10414107497, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1520, .month = 3, .day = 27 }, (try DateTime.fromUnix(-14193188705, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2628, .month = 11, .day = 21 }, (try DateTime.fromUnix(20792540664, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1807, .month = 2, .day = 21 }, (try DateTime.fromUnix(-5139411928, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2249, .month = 12, .day = 12 }, (try DateTime.fromUnix(8834245007, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1694, .month = 11, .day = 17 }, (try DateTime.fromUnix(-8681990253, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2725, .month = 6, .day = 10 }, (try DateTime.fromUnix(23839369640, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1947, .month = 2, .day = 16 }, (try DateTime.fromUnix(-721811319, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2293, .month = 9, .day = 28 }, (try DateTime.fromUnix(10216323340, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1614, .month = 8, .day = 12 }, (try DateTime.fromUnix(-11214942944, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2923, .month = 6, .day = 24 }, (try DateTime.fromUnix(30088834422, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1120, .month = 4, .day = 16 }, (try DateTime.fromUnix(-26814276389, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2035, .month = 12, .day = 9 }, (try DateTime.fromUnix(2080850037, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1167, .month = 1, .day = 15 }, (try DateTime.fromUnix(-25338977309, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2665, .month = 4, .day = 15 }, (try DateTime.fromUnix(21941133655, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1375, .month = 6, .day = 18 }, (try DateTime.fromUnix(-18761787336, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2189, .month = 6, .day = 13 }, (try DateTime.fromUnix(6925211914, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1938, .month = 1, .day = 12 }, (try DateTime.fromUnix(-1008879186, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2556, .month = 6, .day = 9 }, (try DateTime.fromUnix(18506255391, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1294, .month = 10, .day = 29 }, (try DateTime.fromUnix(-21306371902, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2330, .month = 3, .day = 19 }, (try DateTime.fromUnix(11367189469, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1696, .month = 5, .day = 22 }, (try DateTime.fromUnix(-8634251099, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2759, .month = 5, .day = 14 }, (try DateTime.fromUnix(24909971092, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1641, .month = 1, .day = 31 }, (try DateTime.fromUnix(-10379518549, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2451, .month = 6, .day = 26 }, (try DateTime.fromUnix(15194147684, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1962, .month = 1, .day = 4 }, (try DateTime.fromUnix(-252197440, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2883, .month = 11, .day = 15 }, (try DateTime.fromUnix(28839089617, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1587, .month = 8, .day = 5 }, (try DateTime.fromUnix(-12067604792, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2724, .month = 5, .day = 28 }, (try DateTime.fromUnix(23806729201, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1043, .month = 2, .day = 25 }, (try DateTime.fromUnix(-29248487174, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2927, .month = 3, .day = 9 }, (try DateTime.fromUnix(30205844459, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1451, .month = 6, .day = 16 }, (try DateTime.fromUnix(-16363722083, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2145, .month = 1, .day = 21 }, (try DateTime.fromUnix(5524305523, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1497, .month = 10, .day = 31 }, (try DateTime.fromUnix(-14900125085, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2162, .month = 4, .day = 1 }, (try DateTime.fromUnix(6066812142, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1738, .month = 8, .day = 12 }, (try DateTime.fromUnix(-7301852750, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2100, .month = 2, .day = 7 }, (try DateTime.fromUnix(4105665807, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1847, .month = 9, .day = 29 }, (try DateTime.fromUnix(-3858020808, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2370, .month = 9, .day = 19 }, (try DateTime.fromUnix(12645416176, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1292, .month = 7, .day = 8 }, (try DateTime.fromUnix(-21379166225, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2931, .month = 12, .day = 19 }, (try DateTime.fromUnix(30356691249, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1064, .month = 5, .day = 12 }, (try DateTime.fromUnix(-28579189254, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2295, .month = 5, .day = 13 }, (try DateTime.fromUnix(10267494406, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1449, .month = 12, .day = 4 }, (try DateTime.fromUnix(-16411941423, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2565, .month = 1, .day = 16 }, (try DateTime.fromUnix(18777760055, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1968, .month = 6, .day = 25 }, (try DateTime.fromUnix(-47882241, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2817, .month = 5, .day = 9 }, (try DateTime.fromUnix(26739900891, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1334, .month = 7, .day = 16 }, (try DateTime.fromUnix(-20053254809, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2945, .month = 4, .day = 24 }, (try DateTime.fromUnix(30777844895, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1930, .month = 2, .day = 27 }, (try DateTime.fromUnix(-1257362995, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2768, .month = 10, .day = 19 }, (try DateTime.fromUnix(25207675701, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1372, .month = 6, .day = 12 }, (try DateTime.fromUnix(-18856904218, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2603, .month = 8, .day = 29 }, (try DateTime.fromUnix(19996315706, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1201, .month = 4, .day = 7 }, (try DateTime.fromUnix(-24258926407, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2466, .month = 4, .day = 16 }, (try DateTime.fromUnix(15661407305, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1513, .month = 5, .day = 7 }, (try DateTime.fromUnix(-14410616341, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2619, .month = 9, .day = 11 }, (try DateTime.fromUnix(20502308837, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1501, .month = 5, .day = 13 }, (try DateTime.fromUnix(-14788768973, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2765, .month = 11, .day = 19 }, (try DateTime.fromUnix(25115683551, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1881, .month = 2, .day = 9 }, (try DateTime.fromUnix(-2805094638, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2253, .month = 4, .day = 28 }, (try DateTime.fromUnix(8940802800, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1941, .month = 11, .day = 23 }, (try DateTime.fromUnix(-886973505, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2565, .month = 1, .day = 18 }, (try DateTime.fromUnix(18777963967, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1313, .month = 5, .day = 20 }, (try DateTime.fromUnix(-20720877804, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2401, .month = 5, .day = 6 }, (try DateTime.fromUnix(13611949193, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1146, .month = 11, .day = 2 }, (try DateTime.fromUnix(-25976564837, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2115, .month = 6, .day = 11 }, (try DateTime.fromUnix(4589719542, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1276, .month = 8, .day = 1 }, (try DateTime.fromUnix(-21882043432, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2224, .month = 4, .day = 26 }, (try DateTime.fromUnix(8025468043, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1336, .month = 6, .day = 19 }, (try DateTime.fromUnix(-19992405201, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2717, .month = 5, .day = 5 }, (try DateTime.fromUnix(23583761778, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1222, .month = 3, .day = 15 }, (try DateTime.fromUnix(-23598239244, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2841, .month = 8, .day = 29 }, (try DateTime.fromUnix(27506984246, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1818, .month = 7, .day = 28 }, (try DateTime.fromUnix(-4778656923, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2533, .month = 5, .day = 13 }, (try DateTime.fromUnix(17778031068, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1146, .month = 7, .day = 28 }, (try DateTime.fromUnix(-25984946441, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2451, .month = 2, .day = 1 }, (try DateTime.fromUnix(15181688532, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1091, .month = 8, .day = 28 }, (try DateTime.fromUnix(-27717880960, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2168, .month = 4, .day = 12 }, (try DateTime.fromUnix(6257133476, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1718, .month = 10, .day = 16 }, (try DateTime.fromUnix(-7927438165, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2614, .month = 8, .day = 21 }, (try DateTime.fromUnix(20342724001, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1869, .month = 5, .day = 4 }, (try DateTime.fromUnix(-3176499822, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2504, .month = 4, .day = 20 }, (try DateTime.fromUnix(16860953121, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1401, .month = 5, .day = 2 }, (try DateTime.fromUnix(-17945432544, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2467, .month = 8, .day = 2 }, (try DateTime.fromUnix(15702325347, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1654, .month = 3, .day = 12 }, (try DateTime.fromUnix(-9965864717, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2371, .month = 9, .day = 2 }, (try DateTime.fromUnix(12675412066, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1784, .month = 1, .day = 16 }, (try DateTime.fromUnix(-5868249970, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2907, .month = 8, .day = 25 }, (try DateTime.fromUnix(29589265328, .seconds)).date()); + try testing.expectEqual(Date{ .year = 987, .month = 4, .day = 9 }, (try DateTime.fromUnix(-31011963272, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1980, .month = 10, .day = 19 }, (try DateTime.fromUnix(340838803, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1386, .month = 5, .day = 18 }, (try DateTime.fromUnix(-18417299412, .seconds)).date()); + try testing.expectEqual(Date{ .year = 2622, .month = 2, .day = 5 }, (try DateTime.fromUnix(20578157994, .seconds)).date()); + try testing.expectEqual(Date{ .year = 1056, .month = 11, .day = 6 }, (try DateTime.fromUnix(-28816263601, .seconds)).date()); +} + +test "DateTime: time" { + // GO: + // for i := 0; i < 100; i++ { + // us := rand.Int63n(31536000000000000) + // if i%2 == 1 { + // us = -us + // } + // date := time.UnixMicro(us).UTC() + // fmt.Printf("\ttry testing.expectEqual(Time{.hour = %d, .min = %d, .sec = %d, .micros = %d}, (try DateTime.fromUnix(%d, .microseconds)).time());\n", date.Hour(), date.Minute(), date.Second(), date.Nanosecond()/1000, us) + // } + try testing.expectEqual(Time{ .hour = 18, .min = 56, .sec = 18, .micros = 38399 }, (try DateTime.fromUnix(6940752978038399, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 14, .min = 10, .sec = 48, .micros = 481799 }, (try DateTime.fromUnix(-15037004951518201, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 13, .min = 49, .sec = 27, .micros = 814723 }, (try DateTime.fromUnix(26507483367814723, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 3, .min = 53, .sec = 47, .micros = 990825 }, (try DateTime.fromUnix(-15290625972009175, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 9, .min = 28, .sec = 54, .micros = 16606 }, (try DateTime.fromUnix(28046078934016606, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 17, .min = 36, .sec = 38, .micros = 380600 }, (try DateTime.fromUnix(-8638640601619400, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 17, .min = 29, .sec = 27, .micros = 109527 }, (try DateTime.fromUnix(26649192567109527, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 23, .min = 54, .sec = 48, .micros = 10233 }, (try DateTime.fromUnix(-24667200311989767, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 5, .min = 44, .sec = 50, .micros = 913226 }, (try DateTime.fromUnix(22200932690913226, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 5, .min = 36, .sec = 19, .micros = 337687 }, (try DateTime.fromUnix(-13186952620662313, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 20, .min = 6, .sec = 37, .micros = 157270 }, (try DateTime.fromUnix(17827416397157270, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 4, .min = 43, .sec = 33, .micros = 871331 }, (try DateTime.fromUnix(-15558635786128669, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 0, .min = 26, .sec = 54, .micros = 557236 }, (try DateTime.fromUnix(23322644814557236, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 7, .min = 38, .sec = 40, .micros = 370732 }, (try DateTime.fromUnix(-1368030079629268, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 2, .min = 31, .sec = 9, .micros = 223691 }, (try DateTime.fromUnix(20164386669223691, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 12, .min = 41, .sec = 23, .micros = 165207 }, (try DateTime.fromUnix(-20761960716834793, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 0, .min = 46, .sec = 49, .micros = 962075 }, (try DateTime.fromUnix(549247609962075, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 2, .min = 7, .sec = 12, .micros = 984678 }, (try DateTime.fromUnix(-11643688367015322, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 11, .min = 32, .sec = 16, .micros = 343799 }, (try DateTime.fromUnix(4022998336343799, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 17, .min = 26, .sec = 54, .micros = 366277 }, (try DateTime.fromUnix(-8557597985633723, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 16, .min = 1, .sec = 4, .micros = 485152 }, (try DateTime.fromUnix(15070896064485152, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 4, .min = 14, .sec = 18, .micros = 923558 }, (try DateTime.fromUnix(-15995389541076442, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 5, .min = 37, .sec = 58, .micros = 948826 }, (try DateTime.fromUnix(16828148278948826, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 6, .min = 52, .sec = 27, .micros = 1770 }, (try DateTime.fromUnix(-30509975252998230, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 0, .min = 32, .sec = 28, .micros = 381047 }, (try DateTime.fromUnix(7813499548381047, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 14, .min = 1, .sec = 49, .micros = 267686 }, (try DateTime.fromUnix(-14265712690732314, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 4, .min = 53, .sec = 23, .micros = 233239 }, (try DateTime.fromUnix(31107646403233239, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 3, .min = 0, .sec = 53, .micros = 292242 }, (try DateTime.fromUnix(-10317099546707758, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 8, .min = 22, .sec = 13, .micros = 966628 }, (try DateTime.fromUnix(11215959733966628, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 17, .min = 32, .sec = 22, .micros = 779813 }, (try DateTime.fromUnix(-15711949657220187, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 1, .min = 6, .sec = 36, .micros = 405828 }, (try DateTime.fromUnix(6872691996405828, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 12, .min = 0, .sec = 55, .micros = 420129 }, (try DateTime.fromUnix(-31068273544579871, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 22, .min = 17, .sec = 6, .micros = 930158 }, (try DateTime.fromUnix(26304473826930158, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 12, .min = 45, .sec = 25, .micros = 203619 }, (try DateTime.fromUnix(-5358482074796381, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 19, .min = 28, .sec = 0, .micros = 476749 }, (try DateTime.fromUnix(9134623680476749, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 11, .min = 58, .sec = 41, .micros = 864572 }, (try DateTime.fromUnix(-29314353678135428, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 6, .min = 19, .sec = 27, .micros = 566937 }, (try DateTime.fromUnix(9005494767566937, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 9, .min = 3, .sec = 17, .micros = 164061 }, (try DateTime.fromUnix(-24631052202835939, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 23, .min = 2, .sec = 41, .micros = 147703 }, (try DateTime.fromUnix(27754959761147703, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 16, .min = 51, .sec = 1, .micros = 710888 }, (try DateTime.fromUnix(-29839475338289112, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 1, .min = 31, .sec = 44, .micros = 244667 }, (try DateTime.fromUnix(13143000704244667, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 14, .min = 40, .sec = 45, .micros = 594500 }, (try DateTime.fromUnix(-27029323154405500, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 3, .min = 28, .sec = 18, .micros = 941443 }, (try DateTime.fromUnix(26929337298941443, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 18, .min = 34, .sec = 26, .micros = 418287 }, (try DateTime.fromUnix(-16849401933581713, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 16, .min = 51, .sec = 12, .micros = 390293 }, (try DateTime.fromUnix(24013471872390293, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 5, .min = 27, .sec = 59, .micros = 116472 }, (try DateTime.fromUnix(-4881839520883528, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 22, .min = 38, .sec = 58, .micros = 829840 }, (try DateTime.fromUnix(28012689538829840, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 13, .min = 31, .sec = 51, .micros = 397163 }, (try DateTime.fromUnix(-14000034488602837, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 16, .min = 25, .sec = 36, .micros = 566333 }, (try DateTime.fromUnix(3819630336566333, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 23, .min = 52, .sec = 35, .micros = 404576 }, (try DateTime.fromUnix(-24790838844595424, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 14, .min = 17, .sec = 56, .micros = 248627 }, (try DateTime.fromUnix(4303462676248627, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 22, .min = 56, .sec = 31, .micros = 445770 }, (try DateTime.fromUnix(-7573827808554230, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 1, .min = 36, .sec = 32, .micros = 60901 }, (try DateTime.fromUnix(12791180192060901, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 4, .min = 12, .sec = 1, .micros = 816276 }, (try DateTime.fromUnix(-29726596078183724, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 17, .min = 25, .sec = 2, .micros = 88680 }, (try DateTime.fromUnix(9072494702088680, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 7, .min = 14, .sec = 18, .micros = 149127 }, (try DateTime.fromUnix(-20968821941850873, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 15, .min = 45, .sec = 55, .micros = 818121 }, (try DateTime.fromUnix(14590424755818121, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 13, .min = 45, .sec = 5, .micros = 544234 }, (try DateTime.fromUnix(-21099694494455766, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 20, .min = 58, .sec = 32, .micros = 361661 }, (try DateTime.fromUnix(27070837112361661, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 18, .min = 42, .sec = 3, .micros = 375293 }, (try DateTime.fromUnix(-22783699076624707, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 15, .min = 5, .sec = 18, .micros = 844868 }, (try DateTime.fromUnix(3924515118844868, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 17, .min = 39, .sec = 15, .micros = 454348 }, (try DateTime.fromUnix(-19519510844545652, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 22, .min = 34, .sec = 57, .micros = 584438 }, (try DateTime.fromUnix(25405223697584438, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 12, .min = 58, .sec = 48, .micros = 604253 }, (try DateTime.fromUnix(-23848167671395747, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 21, .min = 6, .sec = 10, .micros = 130143 }, (try DateTime.fromUnix(9179039170130143, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 11, .min = 40, .sec = 45, .micros = 806457 }, (try DateTime.fromUnix(-10457900354193543, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 5, .min = 32, .sec = 3, .micros = 84471 }, (try DateTime.fromUnix(20206560723084471, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 11, .min = 8, .sec = 48, .micros = 571978 }, (try DateTime.fromUnix(-13147966271428022, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 10, .min = 37, .sec = 9, .micros = 847397 }, (try DateTime.fromUnix(9639599829847397, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 20, .min = 15, .sec = 37, .micros = 731453 }, (try DateTime.fromUnix(-17972509462268547, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 0, .min = 36, .sec = 51, .micros = 658834 }, (try DateTime.fromUnix(23080639011658834, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 3, .min = 6, .sec = 2, .micros = 359939 }, (try DateTime.fromUnix(-13484004837640061, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 1, .min = 24, .sec = 8, .micros = 76822 }, (try DateTime.fromUnix(22642161848076822, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 5, .min = 20, .sec = 47, .micros = 940649 }, (try DateTime.fromUnix(-9576815952059351, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 16, .min = 19, .sec = 30, .micros = 228423 }, (try DateTime.fromUnix(11237847570228423, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 16, .min = 54, .sec = 33, .micros = 913828 }, (try DateTime.fromUnix(-9146156726086172, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 20, .min = 14, .sec = 10, .micros = 663120 }, (try DateTime.fromUnix(12400805650663120, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 15, .min = 22, .sec = 22, .micros = 500411 }, (try DateTime.fromUnix(-13183893457499589, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 18, .min = 42, .sec = 11, .micros = 637021 }, (try DateTime.fromUnix(17415888131637021, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 22, .min = 7, .sec = 43, .micros = 497651 }, (try DateTime.fromUnix(-3828045136502349, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 9, .min = 25, .sec = 22, .micros = 960397 }, (try DateTime.fromUnix(25585406722960397, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 20, .min = 36, .sec = 31, .micros = 312572 }, (try DateTime.fromUnix(-11209202608687428, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 5, .min = 25, .sec = 18, .micros = 104173 }, (try DateTime.fromUnix(7748544318104173, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 11, .min = 23, .sec = 25, .micros = 504363 }, (try DateTime.fromUnix(-22111446994495637, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 19, .min = 48, .sec = 44, .micros = 703684 }, (try DateTime.fromUnix(21347696924703684, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 12, .min = 10, .sec = 21, .micros = 67035 }, (try DateTime.fromUnix(-29976004178932965, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 6, .min = 0, .sec = 55, .micros = 355102 }, (try DateTime.fromUnix(15622869655355102, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 21, .min = 12, .sec = 1, .micros = 574873 }, (try DateTime.fromUnix(-28386384478425127, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 22, .min = 29, .sec = 45, .micros = 886627 }, (try DateTime.fromUnix(27787703385886627, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 8, .min = 43, .sec = 51, .micros = 403514 }, (try DateTime.fromUnix(-591981368596486, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 12, .min = 1, .sec = 19, .micros = 667089 }, (try DateTime.fromUnix(411998479667089, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 14, .min = 15, .sec = 53, .micros = 366760 }, (try DateTime.fromUnix(-29916899046633240, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 19, .min = 31, .sec = 23, .micros = 639485 }, (try DateTime.fromUnix(29847555083639485, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 0, .min = 21, .sec = 29, .micros = 207122 }, (try DateTime.fromUnix(-13356229110792878, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 10, .min = 35, .sec = 51, .micros = 789976 }, (try DateTime.fromUnix(2401353351789976, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 23, .min = 51, .sec = 4, .micros = 23674 }, (try DateTime.fromUnix(-8687002135976326, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 3, .min = 23, .sec = 21, .micros = 985741 }, (try DateTime.fromUnix(7637772201985741, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 22, .min = 3, .sec = 34, .micros = 497666 }, (try DateTime.fromUnix(-22331814985502334, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 17, .min = 15, .sec = 11, .micros = 818441 }, (try DateTime.fromUnix(14544983711818441, .microseconds)).time()); + try testing.expectEqual(Time{ .hour = 17, .min = 47, .sec = 39, .micros = 303089 }, (try DateTime.fromUnix(-19977775940696911, .microseconds)).time()); +} + +test "DateTime: parse RFC822" { + // try testing.expectError(error.InvalidDateTime, DateTime.parse("", .rfc822)); + // try testing.expectError(error.InvalidDateTime, DateTime.parse("nope", .rfc822)); + try testing.expectError(error.InvalidDate, DateTime.parse("Oth, 01 Jan 20 10:10 Z", .rfc822)); + try testing.expectError(error.InvalidDate, DateTime.parse("Mon , 01 Jan 20 10:10 Z", .rfc822)); + try testing.expectError(error.InvalidDate, DateTime.parse("Mon, 01 Jan 20 10:10 Z", .rfc822)); + try testing.expectError(error.InvalidDate, DateTime.parse(" Mon, 1 Jan 20 10:10 Z", .rfc822)); + try testing.expectError(error.InvalidDate, DateTime.parse("Wed, 1 Jan 20 10:10 Z", .rfc822)); + try testing.expectError(error.InvalidDate, DateTime.parse("Wed, 01 Jan 20 10:10 Z", .rfc822)); + try testing.expectError(error.InvalidDate, DateTime.parse("Wed, 01 J 20 10:10 Z", .rfc822)); + try testing.expectError(error.InvalidDate, DateTime.parse("Wed, 01 Ja 20 10:10 Z", .rfc822)); + try testing.expectError(error.InvalidDate, DateTime.parse("Wed, 01 Jan 2 10:10 Z", .rfc822)); + try testing.expectError(error.InvalidDate, DateTime.parse("Wed, 01 Jan 20 10:10 Z", .rfc822)); + try testing.expectError(error.InvalidTime, DateTime.parse("Wed, 01 Jan 20 10:10 Z", .rfc822)); + try testing.expectError(error.InvalidTime, DateTime.parse("Wed, 01 Jan 20 1:10 Z", .rfc822)); + try testing.expectError(error.InvalidTime, DateTime.parse("Wed, 01 Jan 20 a:10 Z", .rfc822)); + try testing.expectError(error.InvalidTime, DateTime.parse("Wed, 01 Jan 20 1a:10 Z", .rfc822)); + try testing.expectError(error.InvalidTime, DateTime.parse("Wed, 01 Jan 20 200:10 Z", .rfc822)); + try testing.expectError(error.InvalidTime, DateTime.parse("Wed, 01 Jan 20 20:1 Z", .rfc822)); + try testing.expectError(error.InvalidTime, DateTime.parse("Wed, 01 Jan 20 20:001 Z", .rfc822)); + try testing.expectError(error.InvalidTime, DateTime.parse("Wed, 01 Jan 20 20:a Z", .rfc822)); + try testing.expectError(error.InvalidTime, DateTime.parse("Wed, 01 Jan 20 20:1a Z", .rfc822)); + try testing.expectError(error.InvalidTime, DateTime.parse("Wed, 01 Jan 20 20:1a: Z", .rfc822)); + try testing.expectError(error.InvalidTime, DateTime.parse("Wed, 01 Jan 20 20:1a:1 Z", .rfc822)); + try testing.expectError(error.InvalidTime, DateTime.parse("Wed, 01 Jan 20 20:1a:a Z", .rfc822)); + try testing.expectError(error.InvalidTime, DateTime.parse("Wed, 01 Jan 20 20:1a:999 Z", .rfc822)); + try testing.expectError(error.InvalidTime, DateTime.parse("Wed, 01 Jan 20 20:1a:999 Z", .rfc822)); + try testing.expectError(error.InvalidTime, DateTime.parse("Wed, 01 Jan 20 20:1a:22", .rfc822)); + try testing.expectError(error.InvalidTime, DateTime.parse("Wed, 01 Jan 20 20:1a:22 Z", .rfc822)); + try testing.expectError(error.InvalidTime, DateTime.parse("Wed, 01 Jan 20 20:1a:22 X", .rfc822)); + try testing.expectError(error.InvalidTime, DateTime.parse("Wed, 01 Jan 20 20:1a:22 ZZ", .rfc822)); + + { + const dt = try DateTime.parse("31 Dec 68 23:59 Z", .rfc822); + try testing.expectEqual(3124223940000000, dt.micros); + try testing.expectEqual(2068, dt.date().year); + try testing.expectEqual(12, dt.date().month); + try testing.expectEqual(31, dt.date().day); + try testing.expectEqual(23, dt.time().hour); + try testing.expectEqual(59, dt.time().min); + try testing.expectEqual(0, dt.time().sec); + try testing.expectEqual(0, dt.time().micros); + } + + { + const dt = try DateTime.parse("Mon, 31 Dec 68 23:59 Z", .rfc822); + try testing.expectEqual(3124223940000000, dt.micros); + try testing.expectEqual(2068, dt.date().year); + try testing.expectEqual(12, dt.date().month); + try testing.expectEqual(31, dt.date().day); + try testing.expectEqual(23, dt.time().hour); + try testing.expectEqual(59, dt.time().min); + try testing.expectEqual(0, dt.time().sec); + try testing.expectEqual(0, dt.time().micros); + } + + { + const dt = try DateTime.parse("01 Jan 69 01:22:03 GMT", .rfc822); + try testing.expectEqual(-31531077000000, dt.micros); + try testing.expectEqual(1969, dt.date().year); + try testing.expectEqual(1, dt.date().month); + try testing.expectEqual(1, dt.date().day); + try testing.expectEqual(1, dt.time().hour); + try testing.expectEqual(22, dt.time().min); + try testing.expectEqual(3, dt.time().sec); + try testing.expectEqual(0, dt.time().micros); + } + + { + const dt = try DateTime.parse("Sat, 18 Jan 2070 01:22:03 GMT", .rfc822); + try testing.expectEqual(3157233723000000, dt.micros); + try testing.expectEqual(2070, dt.date().year); + try testing.expectEqual(1, dt.date().month); + try testing.expectEqual(18, dt.date().day); + try testing.expectEqual(1, dt.time().hour); + try testing.expectEqual(22, dt.time().min); + try testing.expectEqual(3, dt.time().sec); + try testing.expectEqual(0, dt.time().micros); + } +} + +test "DateTime: parse RFC3339" { + { + const dt = try DateTime.parse("-3221-01-02T03:04:05Z", .rfc3339); + try testing.expectEqual(-163812056155000000, dt.micros); + try testing.expectEqual(-3221, dt.date().year); + try testing.expectEqual(1, dt.date().month); + try testing.expectEqual(2, dt.date().day); + try testing.expectEqual(3, dt.time().hour); + try testing.expectEqual(4, dt.time().min); + try testing.expectEqual(5, dt.time().sec); + try testing.expectEqual(0, dt.time().micros); + } + + { + const dt = try DateTime.parse("0001-02-03T04:05:06.789+00:00", .rfc3339); + try testing.expectEqual(-62132730893211000, dt.micros); + try testing.expectEqual(1, dt.date().year); + try testing.expectEqual(2, dt.date().month); + try testing.expectEqual(3, dt.date().day); + try testing.expectEqual(4, dt.time().hour); + try testing.expectEqual(5, dt.time().min); + try testing.expectEqual(6, dt.time().sec); + try testing.expectEqual(789000, dt.time().micros); + } + + { + const dt = try DateTime.parse("5000-12-31T23:59:58.987654321Z", .rfc3339); + try testing.expectEqual(95649119998987654, dt.micros); + try testing.expectEqual(5000, dt.date().year); + try testing.expectEqual(12, dt.date().month); + try testing.expectEqual(31, dt.date().day); + try testing.expectEqual(23, dt.time().hour); + try testing.expectEqual(59, dt.time().min); + try testing.expectEqual(58, dt.time().sec); + try testing.expectEqual(987654, dt.time().micros); + } + + { + // invalid format + try testing.expectError(error.InvalidDate, DateTime.parse("", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("2023/01-02T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("2023-01/02T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDateTime, DateTime.parse("0001-01-01 T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDateTime, DateTime.parse("0001-01-01t00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDateTime, DateTime.parse("0001-01-01 00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("2023-1-02T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("2023-01-2T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("9-01-2T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("99-01-2T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("999-01-2T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("-999-01-2T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("-1-01-2T00:00Z", .rfc3339)); + } + + // date portion is ISO8601 + try testing.expectError(error.InvalidDate, DateTime.parse("20230102T23:59:58.987654321Z", .rfc3339)); + + { + // invalid month + try testing.expectError(error.InvalidDate, DateTime.parse("2023-00-22T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("2023-0A-22T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("2023-13-22T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("2023-99-22T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("-2023-00-22T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("-2023-13-22T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("-2023-99-22T00:00Z", .rfc3339)); + } + + { + // invalid day + try testing.expectError(error.InvalidDate, DateTime.parse("2023-01-00T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("2023-01-32T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("2023-02-29T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("2023-03-32T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("2023-04-31T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("2023-05-32T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("2023-06-31T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("2023-07-32T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("2023-08-32T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("2023-09-31T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("2023-10-32T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("2023-11-31T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("2023-12-32T00:00Z", .rfc3339)); + } + + { + // valid (max day) + try testing.expectEqual(1675123200000000, (try DateTime.parse("2023-01-31T00:00Z", .rfc3339)).micros); + try testing.expectEqual(1677542400000000, (try DateTime.parse("2023-02-28T00:00Z", .rfc3339)).micros); + try testing.expectEqual(1680220800000000, (try DateTime.parse("2023-03-31T00:00Z", .rfc3339)).micros); + try testing.expectEqual(1682812800000000, (try DateTime.parse("2023-04-30T00:00Z", .rfc3339)).micros); + try testing.expectEqual(1685491200000000, (try DateTime.parse("2023-05-31T00:00Z", .rfc3339)).micros); + try testing.expectEqual(1688083200000000, (try DateTime.parse("2023-06-30T00:00Z", .rfc3339)).micros); + try testing.expectEqual(1690761600000000, (try DateTime.parse("2023-07-31T00:00Z", .rfc3339)).micros); + try testing.expectEqual(1693440000000000, (try DateTime.parse("2023-08-31T00:00Z", .rfc3339)).micros); + try testing.expectEqual(1696032000000000, (try DateTime.parse("2023-09-30T00:00Z", .rfc3339)).micros); + try testing.expectEqual(1698710400000000, (try DateTime.parse("2023-10-31T00:00Z", .rfc3339)).micros); + try testing.expectEqual(1701302400000000, (try DateTime.parse("2023-11-30T00:00Z", .rfc3339)).micros); + try testing.expectEqual(1703980800000000, (try DateTime.parse("2023-12-31T00:00Z", .rfc3339)).micros); + } + + { + // leap years + try testing.expectEqual(951782400000000, (try DateTime.parse("2000-02-29T00:00Z", .rfc3339)).micros); + try testing.expectEqual(13574563200000000, (try DateTime.parse("2400-02-29T00:00Z", .rfc3339)).micros); + try testing.expectEqual(1330473600000000, (try DateTime.parse("2012-02-29T00:00Z", .rfc3339)).micros); + try testing.expectEqual(1709164800000000, (try DateTime.parse("2024-02-29T00:00Z", .rfc3339)).micros); + + try testing.expectError(error.InvalidDate, DateTime.parse("2000-02-30T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("2400-02-30T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("2012-02-30T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("2024-02-30T00:00Z", .rfc3339)); + + try testing.expectError(error.InvalidDate, DateTime.parse("2100-02-29T00:00Z", .rfc3339)); + try testing.expectError(error.InvalidDate, DateTime.parse("2200-02-29T00:00Z", .rfc3339)); + } + + { + // invalid time + try testing.expectError(error.InvalidTime, DateTime.parse("2023-10-10T", .rfc3339)); + try testing.expectError(error.InvalidTime, DateTime.parse("2023-10-10T01:00:", .rfc3339)); + try testing.expectError(error.InvalidTime, DateTime.parse("2023-10-10T1:00:00", .rfc3339)); + try testing.expectError(error.InvalidTime, DateTime.parse("2023-10-10T10:1:00", .rfc3339)); + try testing.expectError(error.InvalidTime, DateTime.parse("2023-10-10T10:11:4", .rfc3339)); + try testing.expectError(error.InvalidTime, DateTime.parse("2023-10-10T10:20:30.", .rfc3339)); + try testing.expectError(error.InvalidDateTime, DateTime.parse("2023-10-10T10:20:30.a", .rfc3339)); + try testing.expectError(error.InvalidTime, DateTime.parse("2023-10-10T10:20:30.1234567899", .rfc3339)); + try testing.expectError(error.InvalidTime, DateTime.parse("2023-10-10T24:00:00", .rfc3339)); + try testing.expectError(error.InvalidTime, DateTime.parse("2023-10-10T00:60:00", .rfc3339)); + try testing.expectError(error.InvalidTime, DateTime.parse("2023-10-10T00:00:60", .rfc3339)); + try testing.expectError(error.InvalidTime, DateTime.parse("2023-10-10T0a:00:00", .rfc3339)); + try testing.expectError(error.InvalidTime, DateTime.parse("2023-10-10T00:0a:00", .rfc3339)); + try testing.expectError(error.InvalidTime, DateTime.parse("2023-10-10T00:00:0a", .rfc3339)); + try testing.expectError(error.InvalidTime, DateTime.parse("2023-10-10T00/00:00", .rfc3339)); + try testing.expectError(error.InvalidDateTime, DateTime.parse("2023-10-10T00:00 00", .rfc3339)); + } +} + +test "DateTime: json" { + { + // DateTime, time no fraction + const dt = try DateTime.parse("2023-09-22T23:59:02Z", .rfc3339); + const out = try std.json.stringifyAlloc(testing.allocator, dt, .{}); + defer testing.allocator.free(out); + try testing.expectString("\"2023-09-22T23:59:02Z\"", out); + } + + { + // time, milliseconds only + const dt = try DateTime.parse("2023-09-22T07:09:32.202Z", .rfc3339); + const out = try std.json.stringifyAlloc(testing.allocator, dt, .{}); + defer testing.allocator.free(out); + try testing.expectString("\"2023-09-22T07:09:32.202Z\"", out); + } + + { + // time, micros + const dt = try DateTime.parse("-0004-12-03T01:02:03.123456Z", .rfc3339); + const out = try std.json.stringifyAlloc(testing.allocator, dt, .{}); + defer testing.allocator.free(out); + try testing.expectString("\"-0004-12-03T01:02:03.123456Z\"", out); + } + + { + // parse + const ts = try std.json.parseFromSlice(TestStruct, testing.allocator, "{\"datetime\":\"2023-09-22T07:09:32.202Z\"}", .{}); + defer ts.deinit(); + try testing.expectEqual(try DateTime.parse("2023-09-22T07:09:32.202Z", .rfc3339), ts.value.datetime.?); + } +} + +test "DateTime: format" { + { + var buf: [30]u8 = undefined; + const out = try std.fmt.bufPrint(&buf, "{s}", .{try DateTime.initUTC(2023, 5, 22, 23, 59, 59, 0)}); + try testing.expectString("2023-05-22T23:59:59Z", out); + } + + { + var buf: [30]u8 = undefined; + const out = try std.fmt.bufPrint(&buf, "{s}", .{try DateTime.initUTC(2023, 5, 22, 8, 9, 10, 12)}); + try testing.expectString("2023-05-22T08:09:10.000012Z", out); + } + + { + var buf: [30]u8 = undefined; + const out = try std.fmt.bufPrint(&buf, "{s}", .{try DateTime.initUTC(2023, 5, 22, 8, 9, 10, 123)}); + try testing.expectString("2023-05-22T08:09:10.000123Z", out); + } + + { + var buf: [30]u8 = undefined; + const out = try std.fmt.bufPrint(&buf, "{s}", .{try DateTime.initUTC(2023, 5, 22, 8, 9, 10, 1234)}); + try testing.expectString("2023-05-22T08:09:10.001234Z", out); + } + + { + var buf: [30]u8 = undefined; + const out = try std.fmt.bufPrint(&buf, "{s}", .{try DateTime.initUTC(-102, 12, 9, 8, 9, 10, 12345)}); + try testing.expectString("-0102-12-09T08:09:10.012345Z", out); + } + + { + var buf: [30]u8 = undefined; + const out = try std.fmt.bufPrint(&buf, "{s}", .{try DateTime.initUTC(-102, 12, 9, 8, 9, 10, 123456)}); + try testing.expectString("-0102-12-09T08:09:10.123456Z", out); + } +} + +test "DateTime: order" { + { + const a = try DateTime.initUTC(2023, 11, 23, 19, 17, 22, 101002); + const b = try DateTime.initUTC(2023, 11, 23, 19, 17, 22, 101002); + try testing.expectEqual(std.math.Order.eq, a.order(b)); + } + + { + const a = try DateTime.initUTC(2023, 5, 22, 12, 59, 2, 492); + const b = try DateTime.initUTC(2022, 5, 22, 23, 59, 2, 492); + try testing.expectEqual(std.math.Order.gt, a.order(b)); + try testing.expectEqual(std.math.Order.lt, b.order(a)); + } + + { + const a = try DateTime.initUTC(2022, 6, 22, 23, 59, 2, 492); + const b = try DateTime.initUTC(2022, 5, 22, 23, 33, 2, 492); + try testing.expectEqual(std.math.Order.gt, a.order(b)); + try testing.expectEqual(std.math.Order.lt, b.order(a)); + } + + { + const a = try DateTime.initUTC(2023, 5, 23, 23, 59, 2, 492); + const b = try DateTime.initUTC(2022, 5, 22, 23, 59, 11, 492); + try testing.expectEqual(std.math.Order.gt, a.order(b)); + try testing.expectEqual(std.math.Order.lt, b.order(a)); + } + + { + const a = try DateTime.initUTC(2023, 11, 23, 20, 17, 22, 101002); + const b = try DateTime.initUTC(2023, 11, 23, 19, 17, 22, 101002); + try testing.expectEqual(std.math.Order.gt, a.order(b)); + try testing.expectEqual(std.math.Order.lt, b.order(a)); + } + + { + const a = try DateTime.initUTC(2023, 11, 23, 19, 18, 22, 101002); + const b = try DateTime.initUTC(2023, 11, 23, 19, 17, 22, 101002); + try testing.expectEqual(std.math.Order.gt, a.order(b)); + try testing.expectEqual(std.math.Order.lt, b.order(a)); + } + + { + const a = try DateTime.initUTC(2023, 11, 23, 19, 17, 23, 101002); + const b = try DateTime.initUTC(2023, 11, 23, 19, 17, 22, 101002); + try testing.expectEqual(std.math.Order.gt, a.order(b)); + try testing.expectEqual(std.math.Order.lt, b.order(a)); + } + + { + const a = try DateTime.initUTC(2023, 11, 23, 19, 17, 22, 101003); + const b = try DateTime.initUTC(2023, 11, 23, 19, 17, 22, 101002); + try testing.expectEqual(std.math.Order.gt, a.order(b)); + try testing.expectEqual(std.math.Order.lt, b.order(a)); + } +} + +test "DateTime: unix" { + { + const dt = try DateTime.initUTC(-4322, 1, 1, 0, 0, 0, 0); + try testing.expectEqual(-198556272000, dt.unix(.seconds)); + try testing.expectEqual(-198556272000000, dt.unix(.milliseconds)); + try testing.expectEqual(-198556272000000000, dt.unix(.microseconds)); + } + + { + const dt = try DateTime.initUTC(1970, 1, 1, 0, 0, 0, 0); + try testing.expectEqual(0, dt.unix(.seconds)); + try testing.expectEqual(0, dt.unix(.milliseconds)); + try testing.expectEqual(0, dt.unix(.microseconds)); + } + + { + const dt = try DateTime.initUTC(2023, 11, 24, 12, 6, 14, 918000); + try testing.expectEqual(1700827574, dt.unix(.seconds)); + try testing.expectEqual(1700827574918, dt.unix(.milliseconds)); + try testing.expectEqual(1700827574918000, dt.unix(.microseconds)); + } + + // microseconds + // GO: + // for i := 0; i < 50; i++ { + // us := rand.Int63n(3153600000000000) + // if i%2 == 1 { + // us = -us + // } + // date := time.UnixMicro(us).UTC() + // fmt.Printf("\ttry testing.expectEqual(%d, (try DateTime.parse(\"%s\", .rfc3339)).unix(.microseconds));\n", us, date.Format(time.RFC3339Nano)) + // } + try testing.expectEqual(2568689002670356, (try DateTime.parse("2051-05-26T04:43:22.670356Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(-2994122503199268, (try DateTime.parse("1875-02-13T19:18:16.800732Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(2973860981156244, (try DateTime.parse("2064-03-27T16:29:41.156244Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(-2122539648627924, (try DateTime.parse("1902-09-28T13:39:11.372076Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(1440540448439442, (try DateTime.parse("2015-08-25T22:07:28.439442Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(-843471236299718, (try DateTime.parse("1943-04-10T14:26:03.700282Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(2428009970341301, (try DateTime.parse("2046-12-09T23:12:50.341301Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(-861640488391156, (try DateTime.parse("1942-09-12T07:25:11.608844Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(107457228254516, (try DateTime.parse("1973-05-28T17:13:48.254516Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(-858997335483954, (try DateTime.parse("1942-10-12T21:37:44.516046Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(1879201014676957, (try DateTime.parse("2029-07-20T00:16:54.676957Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(-2779215184508509, (try DateTime.parse("1881-12-06T03:46:55.491491Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(790920073212180, (try DateTime.parse("1995-01-24T04:01:13.21218Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(-1986764905311346, (try DateTime.parse("1907-01-17T00:51:34.688654Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(1567001594851223, (try DateTime.parse("2019-08-28T14:13:14.851223Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(-2786308994565191, (try DateTime.parse("1881-09-15T01:16:45.434809Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(1190930851203854, (try DateTime.parse("2007-09-27T22:07:31.203854Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(-13894507787609, (try DateTime.parse("1969-07-24T04:24:52.212391Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(1283185581222987, (try DateTime.parse("2010-08-30T16:26:21.222987Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(-3080071240438154, (try DateTime.parse("1872-05-25T00:39:19.561846Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(3091078494301752, (try DateTime.parse("2067-12-14T08:54:54.301752Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(-2788286096253476, (try DateTime.parse("1881-08-23T04:05:03.746524Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(1226140349962650, (try DateTime.parse("2008-11-08T10:32:29.96265Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(-173789078990530, (try DateTime.parse("1964-06-29T13:15:21.00947Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(2202006978733437, (try DateTime.parse("2039-10-12T04:36:18.733437Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(-1957390566907891, (try DateTime.parse("1907-12-23T00:23:53.092109Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(2704228013874812, (try DateTime.parse("2055-09-10T22:26:53.874812Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(-2162891323622724, (try DateTime.parse("1901-06-18T12:51:16.377276Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(2985526644225853, (try DateTime.parse("2064-08-09T16:57:24.225853Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(-2714126911982044, (try DateTime.parse("1883-12-29T11:51:28.017956Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(1389358847381035, (try DateTime.parse("2014-01-10T13:00:47.381035Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(-2599632972496238, (try DateTime.parse("1887-08-15T15:43:47.503762Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(2842567982275671, (try DateTime.parse("2060-01-29T02:13:02.275671Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(-2924719405531619, (try DateTime.parse("1877-04-27T01:56:34.468381Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(929389345478708, (try DateTime.parse("1999-06-14T19:42:25.478708Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(-2928161617689577, (try DateTime.parse("1877-03-18T05:46:22.310423Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(1981926664387480, (try DateTime.parse("2032-10-20T23:11:04.38748Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(-3077852548046313, (try DateTime.parse("1872-06-19T16:57:31.953687Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(323327680783683, (try DateTime.parse("1980-03-31T05:14:40.783683Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(-1282955701919591, (try DateTime.parse("1929-05-06T23:24:58.080409Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(1382921217423641, (try DateTime.parse("2013-10-28T00:46:57.423641Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(-1431006940775286, (try DateTime.parse("1924-08-27T10:04:19.224714Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(3074639946025509, (try DateTime.parse("2067-06-07T02:39:06.025509Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(-2634608860053384, (try DateTime.parse("1886-07-06T20:12:19.946616Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(2779915686281386, (try DateTime.parse("2058-02-02T22:48:06.281386Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(-2016252325938190, (try DateTime.parse("1906-02-09T17:54:34.06181Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(342848400150959, (try DateTime.parse("1980-11-12T03:40:00.150959Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(-2645960576992651, (try DateTime.parse("1886-02-25T10:57:03.007349Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(2460926767780856, (try DateTime.parse("2047-12-25T22:46:07.780856Z", .rfc3339)).unix(.microseconds)); + try testing.expectEqual(-3072719558320472, (try DateTime.parse("1872-08-18T02:47:21.679528Z", .rfc3339)).unix(.microseconds)); + + // milliseconds + // GO + // for i := 0; i < 50; i++ { + // us := rand.Int63n(3153600000000000) + // if i%2 == 1 { + // us = -us + // } + // date := time.UnixMicro(us).UTC() + // fmt.Printf("\ttry testing.expectEqual(%d, (try DateTime.parse(\"%s\", .rfc3339)).unix(.milliseconds));\n", us/1000, date.Format(time.RFC3339Nano)) + // } + try testing.expectEqual(1397526377500, (try DateTime.parse("2014-04-15T01:46:17.500928Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(-586731476093, (try DateTime.parse("1951-05-30T03:02:03.906951Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(2626709817261, (try DateTime.parse("2053-03-27T17:36:57.261986Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(-2699459388451, (try DateTime.parse("1884-06-16T06:10:11.548899Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(187068511670, (try DateTime.parse("1975-12-06T03:28:31.670454Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(-785593098555, (try DateTime.parse("1945-02-08T11:41:41.444519Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(2482013929293, (try DateTime.parse("2048-08-26T00:18:49.293566Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(-39404841784, (try DateTime.parse("1968-10-01T22:12:38.215367Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(1534769380821, (try DateTime.parse("2018-08-20T12:49:40.821612Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(-1980714497790, (try DateTime.parse("1907-03-28T01:31:42.209908Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(1981870811721, (try DateTime.parse("2032-10-20T07:40:11.721424Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(-554657243269, (try DateTime.parse("1952-06-04T08:32:36.730587Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(78531146024, (try DateTime.parse("1972-06-27T22:12:26.024177Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(-2360798362731, (try DateTime.parse("1895-03-10T22:40:37.268319Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(2843392029355, (try DateTime.parse("2060-02-07T15:07:09.355931Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(-1289360209568, (try DateTime.parse("1929-02-21T20:23:10.431793Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(2440116994057, (try DateTime.parse("2047-04-29T02:16:34.057859Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(-1958937239211, (try DateTime.parse("1907-12-05T02:46:00.788847Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(2092930144205, (try DateTime.parse("2036-04-27T17:29:04.205599Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(-1314934006371, (try DateTime.parse("1928-05-01T20:33:13.628366Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(1987707686213, (try DateTime.parse("2032-12-26T21:01:26.21383Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(-2863567343704, (try DateTime.parse("1879-04-04T20:37:36.295226Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(1776340450602, (try DateTime.parse("2026-04-16T11:54:10.602059Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(-135109264096, (try DateTime.parse("1965-09-20T05:38:55.903281Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(664556549013, (try DateTime.parse("1991-01-22T15:02:29.013079Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(-1265741428742, (try DateTime.parse("1929-11-22T05:09:31.257333Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(677440942549, (try DateTime.parse("1991-06-20T18:02:22.549734Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(-3086845293210, (try DateTime.parse("1872-03-07T14:58:26.789666Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(2662366721158, (try DateTime.parse("2054-05-14T10:18:41.158507Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(-35310777646, (try DateTime.parse("1968-11-18T07:27:02.353055Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(466748318057, (try DateTime.parse("1984-10-16T04:18:38.057985Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(-1142849776788, (try DateTime.parse("1933-10-14T13:43:43.211425Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(299657172861, (try DateTime.parse("1979-07-01T06:06:12.86151Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(-2674956599650, (try DateTime.parse("1885-03-26T20:30:00.34904Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(2608306771546, (try DateTime.parse("2052-08-26T17:39:31.546441Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(-2890194900832, (try DateTime.parse("1878-05-31T16:04:59.167405Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(396552033685, (try DateTime.parse("1982-07-26T17:20:33.68525Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(-107099840493, (try DateTime.parse("1966-08-10T10:02:39.506219Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(3003275118291, (try DateTime.parse("2065-03-03T03:05:18.291675Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(-1827348315834, (try DateTime.parse("1912-02-05T03:14:44.165534Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(276927903561, (try DateTime.parse("1978-10-11T04:25:03.561761Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(-2769749223625, (try DateTime.parse("1882-03-25T17:12:56.374223Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(2626498021199, (try DateTime.parse("2053-03-25T06:47:01.199662Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(-1394547124859, (try DateTime.parse("1925-10-23T09:47:55.140254Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(272330504585, (try DateTime.parse("1978-08-18T23:21:44.585364Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(-2210407675350, (try DateTime.parse("1899-12-15T13:52:04.649158Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(1506546882755, (try DateTime.parse("2017-09-27T21:14:42.755649Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(-2320627977264, (try DateTime.parse("1896-06-17T21:07:02.735544Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(2719300156090, (try DateTime.parse("2056-03-03T09:09:16.090337Z", .rfc3339)).unix(.milliseconds)); + try testing.expectEqual(-450791776320, (try DateTime.parse("1955-09-19T12:03:43.679144Z", .rfc3339)).unix(.milliseconds)); + + // seconds + // GO + // for i := 0; i < 50; i++ { + // us := rand.Int63n(3153600000000000) + // if i%2 == 1 { + // us = -us + // } + // date := time.UnixMicro(us).UTC() + // fmt.Printf("\ttry testing.expectEqual(%d, (try DateTime.parse(\"%s\", .rfc3339)).unix(.milliseconds));\n", us/1000/1000, date.Format(time.RFC3339Nano)) + // } + try testing.expectEqual(1019355037, (try DateTime.parse("2002-04-21T02:10:37.264298Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(-2639191098, (try DateTime.parse("1886-05-14T19:21:41.481076Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(552479765, (try DateTime.parse("1987-07-05T10:36:05.374475Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(-2842270449, (try DateTime.parse("1879-12-07T08:25:50.857157Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(2287542812, (try DateTime.parse("2042-06-28T04:33:32.585424Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(-1032056861, (try DateTime.parse("1937-04-18T21:32:18.185245Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(2294125759, (try DateTime.parse("2042-09-12T09:09:19.324234Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(-2434666174, (try DateTime.parse("1892-11-05T23:50:25.855342Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(2130180824, (try DateTime.parse("2037-07-02T20:53:44.663679Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(-2088926942, (try DateTime.parse("1903-10-22T14:30:57.110159Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(210188161, (try DateTime.parse("1976-08-29T17:36:01.512348Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(-1594811550, (try DateTime.parse("1919-06-19T12:47:29.692995Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(408055212, (try DateTime.parse("1982-12-06T20:40:12.74791Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(-763370385, (try DateTime.parse("1945-10-23T16:40:14.54824Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(2220686606, (try DateTime.parse("2040-05-15T09:23:26.183323Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(-1829267394, (try DateTime.parse("1912-01-13T22:10:05.152891Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(186103622, (try DateTime.parse("1975-11-24T23:27:02.092278Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(-104963797, (try DateTime.parse("1966-09-04T03:23:22.379643Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(188664629, (try DateTime.parse("1975-12-24T14:50:29.082285Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(-978305356, (try DateTime.parse("1939-01-01T00:30:43.460779Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(1857079750, (try DateTime.parse("2028-11-05T23:29:10.225783Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(-1059764722, (try DateTime.parse("1936-06-02T04:54:37.841836Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(2931563560, (try DateTime.parse("2062-11-24T03:12:40.682221Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(-58861051, (try DateTime.parse("1968-02-19T17:42:28.861019Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(2540374023, (try DateTime.parse("2050-07-02T11:27:03.083527Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(-369803898, (try DateTime.parse("1958-04-13T20:41:41.391534Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(1150522786, (try DateTime.parse("2006-06-17T05:39:46.776689Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(-3094311182, (try DateTime.parse("1871-12-12T05:06:57.955425Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(2742945297, (try DateTime.parse("2056-12-02T01:14:57.552041Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(-3055421456, (try DateTime.parse("1873-03-06T07:49:03.861761Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(1935913185, (try DateTime.parse("2031-05-07T09:39:45.408961Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(-1546803921, (try DateTime.parse("1920-12-26T04:14:38.089431Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(2430955251, (try DateTime.parse("2047-01-13T01:20:51.611416Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(-1162742133, (try DateTime.parse("1933-02-26T08:04:26.776057Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(2820984010, (try DateTime.parse("2059-05-24T06:40:10.9707Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(-2671779872, (try DateTime.parse("1885-05-02T14:55:27.010415Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(419726969, (try DateTime.parse("1983-04-20T22:49:29.184213Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(-2886236400, (try DateTime.parse("1878-07-16T11:39:59.700923Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(1091845921, (try DateTime.parse("2004-08-07T02:32:01.949043Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(-1345585389, (try DateTime.parse("1927-05-13T02:16:50.807413Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(968555612, (try DateTime.parse("2000-09-10T03:13:32.056103Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(-525723150, (try DateTime.parse("1953-05-05T05:47:29.657935Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(2179443523, (try DateTime.parse("2039-01-24T00:58:43.238504Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(-2200838901, (try DateTime.parse("1900-04-05T07:51:38.801707Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(567335109, (try DateTime.parse("1987-12-24T09:05:09.535877Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(-714932675, (try DateTime.parse("1947-05-07T07:35:24.863781Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(2735649359, (try DateTime.parse("2056-09-08T14:35:59.483204Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(-2386101706, (try DateTime.parse("1894-05-22T01:58:13.445088Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(115985094, (try DateTime.parse("1973-09-04T10:04:54.005266Z", .rfc3339)).unix(.seconds)); + try testing.expectEqual(-3046532170, (try DateTime.parse("1873-06-17T05:03:49.260067Z", .rfc3339)).unix(.seconds)); +} + +test "DateTime: limits" { + { + // min + const dt1 = try DateTime.initUTC(-4712, 1, 1, 0, 0, 0, 0); + const dt2 = try DateTime.parse("-4712-01-01T00:00:00.000000Z", .rfc3339); + const dt3 = try DateTime.fromUnix(-210863520000, .seconds); + const dt4 = try DateTime.fromUnix(-210863520000000, .milliseconds); + const dt5 = try DateTime.fromUnix(-210863520000000000, .microseconds); + for ([_]DateTime{ dt1, dt2, dt3, dt4, dt5 }) |dt| { + try testing.expectEqual(-4712, dt.date().year); + try testing.expectEqual(1, dt.date().month); + try testing.expectEqual(1, dt.date().day); + try testing.expectEqual(0, dt.time().hour); + try testing.expectEqual(0, dt.time().min); + try testing.expectEqual(0, dt.time().sec); + try testing.expectEqual(0, dt.time().micros); + try testing.expectEqual(-210863520000, dt.unix(.seconds)); + try testing.expectEqual(-210863520000000, dt.unix(.milliseconds)); + try testing.expectEqual(-210863520000000000, dt.unix(.microseconds)); + } + } + + { + // max + const dt1 = try DateTime.initUTC(9999, 12, 31, 23, 59, 59, 999999); + const dt2 = try DateTime.parse("9999-12-31T23:59:59.999999Z", .rfc3339); + const dt3 = try DateTime.fromUnix(253402300799, .seconds); + const dt4 = try DateTime.fromUnix(253402300799999, .milliseconds); + const dt5 = try DateTime.fromUnix(253402300799999999, .microseconds); + for ([_]DateTime{ dt1, dt2, dt3, dt4, dt5 }, 0..) |dt, i| { + try testing.expectEqual(9999, dt.date().year); + try testing.expectEqual(12, dt.date().month); + try testing.expectEqual(31, dt.date().day); + try testing.expectEqual(23, dt.time().hour); + try testing.expectEqual(59, dt.time().min); + try testing.expectEqual(59, dt.time().sec); + + try testing.expectEqual(253402300799, dt.unix(.seconds)); + + if (i == 2) { + try testing.expectEqual(0, dt.time().micros); + try testing.expectEqual(253402300799000, dt.unix(.milliseconds)); + try testing.expectEqual(253402300799000000, dt.unix(.microseconds)); + } else if (i == 3) { + try testing.expectEqual(999000, dt.time().micros); + try testing.expectEqual(253402300799999, dt.unix(.milliseconds)); + try testing.expectEqual(253402300799999000, dt.unix(.microseconds)); + } else { + try testing.expectEqual(999999, dt.time().micros); + try testing.expectEqual(253402300799999, dt.unix(.milliseconds)); + try testing.expectEqual(253402300799999999, dt.unix(.microseconds)); + } + } + } +} + +test "DateTime: add" { + { + // positive + var dt = try DateTime.parse("2023-11-26T03:13:46.540234Z", .rfc3339); + + dt = try dt.add(800, .microseconds); + try expectDateTime("2023-11-26T03:13:46.541034Z", dt); + + dt = try dt.add(950, .milliseconds); + try expectDateTime("2023-11-26T03:13:47.491034Z", dt); + + dt = try dt.add(32, .seconds); + try expectDateTime("2023-11-26T03:14:19.491034Z", dt); + + dt = try dt.add(1489, .minutes); + try expectDateTime("2023-11-27T04:03:19.491034Z", dt); + + dt = try dt.add(6, .days); + try expectDateTime("2023-12-03T04:03:19.491034Z", dt); + } + + { + // negative + var dt = try DateTime.parse("2023-11-26T03:13:46.540234Z", .rfc3339); + + dt = try dt.add(-800, .microseconds); + try expectDateTime("2023-11-26T03:13:46.539434Z", dt); + + dt = try dt.add(-950, .milliseconds); + try expectDateTime("2023-11-26T03:13:45.589434Z", dt); + + dt = try dt.add(-50, .seconds); + try expectDateTime("2023-11-26T03:12:55.589434Z", dt); + + dt = try dt.add(-1489, .minutes); + try expectDateTime("2023-11-25T02:23:55.589434Z", dt); + + dt = try dt.add(-6, .days); + try expectDateTime("2023-11-19T02:23:55.589434Z", dt); + } +} + +test "DateTime: sub" { + { + const a = try DateTime.parse("2023-11-26T03:13:46.540234Z", .rfc3339); + const b = try DateTime.parse("2023-11-26T03:13:47.540236Z", .rfc3339); + + try testing.expectEqual(-1, a.sub(b, .seconds)); + try testing.expectEqual(-1000, a.sub(b, .milliseconds)); + try testing.expectEqual(-1000002, a.sub(b, .microseconds)); + } + + { + const a = try DateTime.parse("2023-11-27T03:13:47.540234Z", .rfc3339); + const b = try DateTime.parse("2023-11-26T03:13:47.540234Z", .rfc3339); + + try testing.expectEqual(86400, a.sub(b, .seconds)); + try testing.expectEqual(86400000, a.sub(b, .milliseconds)); + try testing.expectEqual(86400000000, a.sub(b, .microseconds)); + } +} + +fn expectDateTime(expected: []const u8, dt: DateTime) !void { + var buf: [30]u8 = undefined; + const actual = try std.fmt.bufPrint(&buf, "{s}", .{dt}); + try testing.expectString(expected, actual); +} + +const TestStruct = struct { + date: ?Date = null, + time: ?Time = null, + datetime: ?DateTime = null, +}; diff --git a/src/storage/cookie.zig b/src/storage/cookie.zig new file mode 100644 index 00000000..3c4481a0 --- /dev/null +++ b/src/storage/cookie.zig @@ -0,0 +1,939 @@ +const std = @import("std"); +const Uri = std.Uri; +const Allocator = std.mem.Allocator; +const ArenaAllocator = std.heap.ArenaAllocator; + +const DateTime = @import("../datetime.zig").DateTime; +const public_suffix_list = @import("../data/public_suffix_list.zig").lookup; + +pub const Jar = struct { + allocator: Allocator, + cookies: std.ArrayListUnmanaged(Cookie), + + pub fn init(allocator: Allocator) Jar { + return .{ + .cookies = .{}, + .allocator = allocator, + }; + } + + pub fn deinit(self: *Jar) void { + for (self.cookies.items) |c| { + c.deinit(); + } + self.cookies.deinit(self.allocator); + } + + pub fn add( + self: *Jar, + cookie: Cookie, + request_time: i64, + ) !void { + const is_expired = isCookieExpired(&cookie, request_time); + defer if (is_expired) { + cookie.deinit(); + }; + + for (self.cookies.items, 0..) |*c, i| { + if (areCookiesEqual(&cookie, c)) { + c.deinit(); + if (is_expired) { + _ = self.cookies.swapRemove(i); + } else { + self.cookies.items[i] = cookie; + } + return; + } + } + + if (!is_expired) { + try self.cookies.append(self.allocator, cookie); + } + } + + pub fn forRequest( + self: *Jar, + allocator: Allocator, + request_time: i64, + origin_uri: ?Uri, + target_uri: Uri, + navigation: bool, + ) !CookieList { + const target_path = target_uri.path.percent_encoded; + const target_host = (target_uri.host orelse return error.InvalidURI).percent_encoded; + + const same_site = try areSameSite(origin_uri, target_host); + const is_secure = std.mem.eql(u8, target_uri.scheme, "https"); + + var matching: std.ArrayListUnmanaged(*Cookie) = .{}; + + var i: usize = 0; + var cookies = self.cookies.items; + while (i < cookies.len) { + const cookie = &cookies[i]; + + if (isCookieExpired(cookie, request_time)) { + cookie.deinit(); + _ = self.cookies.swapRemove(i); + // don't increment i ! + continue; + } + i += 1; + + if (is_secure == false and cookie.secure) { + // secure cookie can only be sent over HTTPs + continue; + } + + if (same_site == false) { + // If we aren't on the "same site" (matching 2nd level domain + // taking into account public suffix list), then the cookie + // can only be sent if cookie.same_site == .none, or if + // we're navigating to (as opposed to, say, loading an image) + // and cookie.same_site == .lax + switch (cookie.same_site) { + .strict => continue, + .lax => if (navigation == false) continue, + .none => {}, + } + } + + { + const domain = cookie.domain; + if (domain[0] == '.') { + // When a Set-Cookie header has a Domain attribute + // Then we will _always_ prefix it with a dot, extending its + // availability to all subdomains (yes, setting the Domain + // attributes EXPANDS the domains which the cookie will be + // sent to, to always include all subdomains). + if (std.mem.eql(u8, target_host, domain[1..]) == false and std.mem.endsWith(u8, target_host, domain) == false) { + continue; + } + } else if (std.mem.eql(u8, target_host, domain) == false) { + // When the Domain attribute isn't specific, then the cookie + // is only sent on an exact match. + continue; + } + } + + { + const path = cookie.path; + if (path[path.len - 1] == '/') { + // If our cookie has a trailing slash, we can only match is + // the target path is a perfix. I.e., if our path is + // /doc/ we can only match /doc/* + if (std.mem.startsWith(u8, target_path, path) == false) { + continue; + } + } else { + // Our cookie path is something like /hello + if (std.mem.startsWith(u8, target_path, path) == false) { + // The target path has to either be /hello (it isn't) + continue; + } else if (target_path.len < path.len or (target_path.len > path.len and target_path[path.len] != '/')) { + // Or it has to be something like /hello/* (it isn't) + // it isn't! + continue; + } + } + } + // we have a match! + try matching.append(allocator, cookie); + } + + return .{ ._cookies = matching }; + } +}; + +pub const CookieList = struct { + _cookies: std.ArrayListUnmanaged(*Cookie), + + pub fn deinit(self: *CookieList, allocator: Allocator) void { + self._cookies.deinit(allocator); + } + + pub fn cookies(self: *const CookieList) []*Cookie { + return self._cookies.items; + } +}; + +fn isCookieExpired(cookie: *const Cookie, now: i64) bool { + const ce = cookie.expires orelse return false; + return ce <= now; +} + +fn areCookiesEqual(a: *const Cookie, b: *const Cookie) bool { + if (std.mem.eql(u8, a.name, b.name) == false) { + return false; + } + if (std.mem.eql(u8, a.domain, b.domain) == false) { + return false; + } + if (std.mem.eql(u8, a.path, b.path) == false) { + return false; + } + return true; +} + +fn areSameSite(origin_uri_: ?std.Uri, target_host: []const u8) !bool { + const origin_uri = origin_uri_ orelse return true; + const origin_host = (origin_uri.host orelse return error.InvalidURI).percent_encoded; + + // common case + if (std.mem.eql(u8, target_host, origin_host)) { + return true; + } + + return std.mem.eql(u8, findSecondLevelDomain(target_host), findSecondLevelDomain(origin_host)); +} + +fn findSecondLevelDomain(host: []const u8) []const u8 { + var i = std.mem.lastIndexOfScalar(u8, host, '.') orelse return host; + while (true) { + i = std.mem.lastIndexOfScalar(u8, host[0..i], '.') orelse return host; + const strip = i + 1; + if (public_suffix_list(host[strip..]) == false) { + return host[strip..]; + } + } +} + +pub const Cookie = struct { + arena: ArenaAllocator, + name: []const u8, + value: []const u8, + path: []const u8, + domain: []const u8, + expires: ?i64, + secure: bool, + http_only: bool, + same_site: SameSite, + + const SameSite = enum { + strict, + lax, + none, + }; + + pub fn deinit(self: *const Cookie) void { + self.arena.deinit(); + } + + // There's https://datatracker.ietf.org/doc/html/rfc6265 but browsers are + // far less strict. I only found 2 cases where browsers will reject a cookie: + // - a byte 0...32 and 127..255 anywhere in the cookie (the HTTP header + // parser might take care of this already) + // - any shenanigans with the domain attribute - it has to be the current + // domain or one of higher order, exluding TLD. + // Anything else, will turn into a cookie. + // Single value? That's a cookie with an emtpy name and a value + // Key or Values with characters the RFC says aren't allowed? Allowed! ( + // (as long as the characters are 32...126) + // Invalid attributes? Ignored. + // Invalid attribute values? Ignore. + // Duplicate attributes - use the last valid + // Value-less attributes with a value? Ignore the value + pub fn parse(allocator: Allocator, uri: std.Uri, str: []const u8) !Cookie { + if (str.len == 0) { + // this check is necessary, `std.mem.minMax` asserts len > 0 + return error.Empty; + } + + const host = (uri.host orelse return error.InvalidURI).percent_encoded; + + { + const min, const max = std.mem.minMax(u8, str); + if (min < 32 or max > 126) { + return error.InvalidByteSequence; + } + } + + const cookie_name, const cookie_value, const rest = parseNameValue(str) catch { + return error.InvalidNameValue; + }; + + var scrap: [8]u8 = undefined; + + var path: ?[]const u8 = null; + var domain: ?[]const u8 = null; + var secure: ?bool = null; + var max_age: ?i64 = null; + var http_only: ?bool = null; + var expires: ?DateTime = null; + var same_site: ?Cookie.SameSite = null; + + var it = std.mem.splitScalar(u8, rest, ';'); + while (it.next()) |attribute| { + const sep = std.mem.indexOfScalarPos(u8, attribute, 0, '=') orelse attribute.len; + const key_string = trim(attribute[0..sep]); + + if (key_string.len > 8) { + // not valid, ignore + continue; + } + + // Make sure no one changes our max length without also expanding the size of scrap + std.debug.assert(key_string.len <= 8); + + const key = std.meta.stringToEnum(enum { + path, + domain, + secure, + @"max-age", + expires, + httponly, + samesite, + }, std.ascii.lowerString(&scrap, key_string)) orelse continue; + + var value = if (sep == attribute.len) "" else trim(attribute[sep + 1 ..]); + switch (key) { + .path => { + // path attribute value either begins with a '/' or we + // ignore it and use the "default-path" algorithm + if (value.len > 0 and value[0] == '/') { + path = value; + } + }, + .domain => { + if (value.len == 0) { + continue; + } + if (value[0] == '.') { + // leading dot is ignored + value = value[1..]; + } + + if (std.mem.indexOfScalarPos(u8, value, 0, '.') == null) { + // can't set a cookie for a TLD + return error.InvalidDomain; + } + + if (std.mem.endsWith(u8, host, value) == false) { + return error.InvalidDomain; + } + domain = value; + }, + .secure => secure = true, + .@"max-age" => max_age = std.fmt.parseInt(i64, value, 10) catch continue, + .expires => expires = DateTime.parse(value, .rfc822) catch continue, + .httponly => http_only = true, + .samesite => { + same_site = std.meta.stringToEnum(Cookie.SameSite, std.ascii.lowerString(&scrap, value)) orelse continue; + }, + } + } + + if (same_site == .none and secure == null) { + return error.InsecureSameSite; + } + + var arena = ArenaAllocator.init(allocator); + errdefer arena.deinit(); + const aa = arena.allocator(); + const owned_name = try aa.dupe(u8, cookie_name); + const owned_value = try aa.dupe(u8, cookie_value); + const owned_path = if (path) |p| + try aa.dupe(u8, p) + else + try defaultPath(aa, uri.path.percent_encoded); + + const owned_domain = if (domain) |d| blk: { + const s = try aa.alloc(u8, d.len + 1); + s[0] = '.'; + @memcpy(s[1..], d); + break :blk s; + } else blk: { + break :blk try aa.dupe(u8, host); + }; + + var normalized_expires: ?i64 = null; + if (max_age) |ma| { + normalized_expires = std.time.timestamp() + ma; + } else { + // max age takes priority over expires + if (expires) |e| { + normalized_expires = e.sub(DateTime.now(), .seconds); + } + } + + return .{ + .arena = arena, + .name = owned_name, + .value = owned_value, + .path = owned_path, + .same_site = same_site orelse .lax, + .secure = secure orelse false, + .http_only = http_only orelse false, + .domain = owned_domain, + .expires = normalized_expires, + }; + } + + fn parseNameValue(str: []const u8) !struct { []const u8, []const u8, []const u8 } { + const key_value_end = std.mem.indexOfScalarPos(u8, str, 0, ';') orelse str.len; + const rest = if (key_value_end == str.len) "" else str[key_value_end + 1 ..]; + + const sep = std.mem.indexOfScalarPos(u8, str[0..key_value_end], 0, '=') orelse { + const value = trim(str[0..key_value_end]); + if (value.len == 0) { + return error.Empty; + } + return .{ "", value, rest }; + }; + + const name = trim(str[0..sep]); + const value = trim(str[sep + 1 .. key_value_end]); + return .{ name, value, rest }; + } +}; + +fn defaultPath(allocator: Allocator, document_path: []const u8) ![]const u8 { + if (document_path.len == 0 or (document_path.len == 1 and document_path[0] == '/')) { + return "/"; + } + const last = std.mem.lastIndexOfScalar(u8, document_path[1..], '/') orelse { + return "/"; + }; + return try allocator.dupe(u8, document_path[0 .. last + 1]); +} + +fn trim(str: []const u8) []const u8 { + return std.mem.trim(u8, str, &std.ascii.whitespace); +} + +fn trimLeft(str: []const u8) []const u8 { + return std.mem.trimLeft(u8, str, &std.ascii.whitespace); +} + +fn trimRight(str: []const u8) []const u8 { + return std.mem.trimLeft(u8, str, &std.ascii.whitespace); +} + +const testing = @import("../testing.zig"); +test "cookie: findSecondLevelDomain" { + const cases = [_]struct { []const u8, []const u8 }{ + .{ "", "" }, + .{ "com", "com" }, + .{ "lightpanda.io", "lightpanda.io" }, + .{ "lightpanda.io", "test.lightpanda.io" }, + .{ "lightpanda.io", "first.test.lightpanda.io" }, + .{ "www.gov.uk", "www.gov.uk" }, + .{ "stats.gov.uk", "www.stats.gov.uk" }, + .{ "api.gov.uk", "api.gov.uk" }, + .{ "dev.api.gov.uk", "dev.api.gov.uk" }, + .{ "dev.api.gov.uk", "1.dev.api.gov.uk" }, + }; + for (cases) |c| { + try testing.expectEqual(c.@"0", findSecondLevelDomain(c.@"1")); + } +} + +test "Jar: add" { + const expectCookies = struct { + fn expect(expected: []const struct { []const u8, []const u8 }, jar: Jar) !void { + try testing.expectEqual(expected.len, jar.cookies.items.len); + LOOP: for (expected) |e| { + for (jar.cookies.items) |c| { + if (std.mem.eql(u8, e.@"0", c.name) and std.mem.eql(u8, e.@"1", c.value)) { + continue :LOOP; + } + } + std.debug.print("Cookie ({s}={s}) not found", .{ e.@"0", e.@"1" }); + return error.CookieNotFound; + } + } + }.expect; + + const now = std.time.timestamp(); + + var jar = Jar.init(testing.allocator); + defer jar.deinit(); + try expectCookies(&.{}, jar); + + try jar.add(try Cookie.parse(testing.allocator, test_uri, "over=9000;Max-Age=0"), now); + try expectCookies(&.{}, jar); + + try jar.add(try Cookie.parse(testing.allocator, test_uri, "over=9000"), now); + try expectCookies(&.{.{ "over", "9000" }}, jar); + + try jar.add(try Cookie.parse(testing.allocator, test_uri, "over=9000!!"), now); + try expectCookies(&.{.{ "over", "9000!!" }}, jar); + + try jar.add(try Cookie.parse(testing.allocator, test_uri, "spice=flow"), now); + try expectCookies(&.{ .{ "over", "9000!!" }, .{ "spice", "flow" } }, jar); + + try jar.add(try Cookie.parse(testing.allocator, test_uri, "spice=flows;Path=/"), now); + try expectCookies(&.{ .{ "over", "9000!!" }, .{ "spice", "flows" } }, jar); + + try jar.add(try Cookie.parse(testing.allocator, test_uri, "over=9001;Path=/other"), now); + try expectCookies(&.{ .{ "over", "9000!!" }, .{ "spice", "flows" }, .{ "over", "9001" } }, jar); + + try jar.add(try Cookie.parse(testing.allocator, test_uri, "over=9002;Path=/;Domain=lightpanda.io"), now); + try expectCookies(&.{ .{ "over", "9000!!" }, .{ "spice", "flows" }, .{ "over", "9001" }, .{ "over", "9002" } }, jar); + + try jar.add(try Cookie.parse(testing.allocator, test_uri, "over=x;Path=/other;Max-Age=-200"), now); + try expectCookies(&.{ .{ "over", "9000!!" }, .{ "spice", "flows" }, .{ "over", "9002" } }, jar); +} + +test "Jar: forRequest" { + const expectCookies = struct { + fn expect(expected: []const []const u8, list: *CookieList) !void { + defer list.deinit(testing.allocator); + const acutal_cookies = list._cookies.items; + + try testing.expectEqual(expected.len, acutal_cookies.len); + LOOP: for (expected) |e| { + for (acutal_cookies) |c| { + if (std.mem.eql(u8, e, c.name)) { + continue :LOOP; + } + } + std.debug.print("Cookie '{s}' not found", .{e}); + return error.CookieNotFound; + } + } + }.expect; + + const now = std.time.timestamp(); + + var jar = Jar.init(testing.allocator); + defer jar.deinit(); + + const test_uri_2 = Uri.parse("http://test.lightpanda.io/") catch unreachable; + + { + // test with no cookies + var matches = try jar.forRequest(testing.allocator, now, test_uri, test_uri, true); + try expectCookies(&.{}, &matches); + } + + try jar.add(try Cookie.parse(testing.allocator, test_uri, "global1=1"), now); + try jar.add(try Cookie.parse(testing.allocator, test_uri, "global2=2;Max-Age=30;domain=lightpanda.io"), now); + try jar.add(try Cookie.parse(testing.allocator, test_uri, "path1=3;Path=/about"), now); + try jar.add(try Cookie.parse(testing.allocator, test_uri, "path2=4;Path=/docs/"), now); + try jar.add(try Cookie.parse(testing.allocator, test_uri, "secure=5;Secure"), now); + try jar.add(try Cookie.parse(testing.allocator, test_uri, "sitenone=6;SameSite=None;Path=/x/;Secure"), now); + try jar.add(try Cookie.parse(testing.allocator, test_uri, "sitelax=7;SameSite=Lax;Path=/x/"), now); + try jar.add(try Cookie.parse(testing.allocator, test_uri, "sitestrict=8;SameSite=Strict;Path=/x/"), now); + try jar.add(try Cookie.parse(testing.allocator, test_uri_2, "domain1=9;domain=test.lightpanda.io"), now); + + { + // nothing fancy here + var matches = try jar.forRequest(testing.allocator, now, test_uri, test_uri, true); + try expectCookies(&.{ "global1", "global2" }, &matches); + } + + { + // We have a cookie where Domain=lightpanda.io + // This should _not_ match xyxlightpanda.io + var matches = try jar.forRequest( + testing.allocator, + now, + test_uri, + try std.Uri.parse("http://anothersitelightpanda.io/"), + true, + ); + try expectCookies(&.{}, &matches); + } + + { + // matching path without trailing / + var matches = try jar.forRequest( + testing.allocator, + now, + test_uri, + try std.Uri.parse("http://lightpanda.io/about"), + true, + ); + try expectCookies(&.{ "global1", "global2", "path1" }, &matches); + } + + { + // incomplete prefix path + var matches = try jar.forRequest( + testing.allocator, + now, + test_uri, + try std.Uri.parse("http://lightpanda.io/abou"), + true, + ); + try expectCookies(&.{ "global1", "global2" }, &matches); + } + + { + // path doesn't match + var matches = try jar.forRequest( + testing.allocator, + now, + test_uri, + try std.Uri.parse("http://lightpanda.io/aboutus"), + true, + ); + try expectCookies(&.{ "global1", "global2" }, &matches); + } + + { + // path doesn't match cookie directory + var matches = try jar.forRequest( + testing.allocator, + now, + test_uri, + try std.Uri.parse("http://lightpanda.io/docs"), + true, + ); + try expectCookies(&.{ "global1", "global2" }, &matches); + } + + { + // exact directory match + var matches = try jar.forRequest( + testing.allocator, + now, + test_uri, + try std.Uri.parse("http://lightpanda.io/docs/"), + true, + ); + try expectCookies(&.{ "global1", "global2", "path2" }, &matches); + } + + { + // sub directory match + var matches = try jar.forRequest( + testing.allocator, + now, + test_uri, + try std.Uri.parse("http://lightpanda.io/docs/more"), + true, + ); + try expectCookies(&.{ "global1", "global2", "path2" }, &matches); + } + + { + // secure + var matches = try jar.forRequest( + testing.allocator, + now, + test_uri, + try std.Uri.parse("https://lightpanda.io/"), + true, + ); + try expectCookies(&.{ "global1", "global2", "secure" }, &matches); + } + + { + // navigational cross domain, secure + var matches = try jar.forRequest( + testing.allocator, + now, + try std.Uri.parse("https://example.com/"), + try std.Uri.parse("https://lightpanda.io/x/"), + true, + ); + try expectCookies(&.{ "global1", "global2", "sitenone", "sitelax", "secure" }, &matches); + } + + { + // navigational cross domain, insecure + var matches = try jar.forRequest( + testing.allocator, + now, + try std.Uri.parse("http://example.com/"), + try std.Uri.parse("http://lightpanda.io/x/"), + true, + ); + try expectCookies(&.{ "global1", "global2", "sitelax" }, &matches); + } + + { + // non-navigational cross domain, insecure + var matches = try jar.forRequest( + testing.allocator, + now, + try std.Uri.parse("http://example.com/"), + try std.Uri.parse("http://lightpanda.io/x/"), + false, + ); + try expectCookies(&.{}, &matches); + } + + { + // non-navigational cross domain, secure + var matches = try jar.forRequest( + testing.allocator, + now, + try std.Uri.parse("https://example.com/"), + try std.Uri.parse("https://lightpanda.io/x/"), + false, + ); + try expectCookies(&.{"sitenone"}, &matches); + } + + { + // non-navigational same origin + var matches = try jar.forRequest( + testing.allocator, + now, + try std.Uri.parse("http://lightpanda.io/"), + try std.Uri.parse("http://lightpanda.io/x/"), + false, + ); + try expectCookies(&.{ "global1", "global2", "sitelax", "sitestrict" }, &matches); + } + + { + // exact domain match + suffix + var matches = try jar.forRequest( + testing.allocator, + now, + test_uri, + try std.Uri.parse("http://test.lightpanda.io/"), + true, + ); + try expectCookies(&.{ "global2", "domain1" }, &matches); + } + + { + // domain suffix match + suffix + var matches = try jar.forRequest( + testing.allocator, + now, + test_uri, + try std.Uri.parse("http://1.test.lightpanda.io/"), + true, + ); + try expectCookies(&.{ "global2", "domain1" }, &matches); + } + + { + // non-matching domain + var matches = try jar.forRequest( + testing.allocator, + now, + test_uri, + try std.Uri.parse("http://other.lightpanda.io/"), + true, + ); + try expectCookies(&.{"global2"}, &matches); + } + + { + // cookie has expired + const l = jar.cookies.items.len; + var matches = try jar.forRequest(testing.allocator, now + 100, test_uri, test_uri, true); + try expectCookies(&.{"global1"}, &matches); + try testing.expectEqual(l - 1, jar.cookies.items.len); + } + + // If you add more cases after this point, note that the above test removes + // the 'global2' cookie +} + +test "Cookie: parse key=value" { + try expectError(error.Empty, null, ""); + try expectError(error.InvalidByteSequence, null, &.{ 'a', 30, '=', 'b' }); + try expectError(error.InvalidByteSequence, null, &.{ 'a', 127, '=', 'b' }); + try expectError(error.InvalidByteSequence, null, &.{ 'a', '=', 'b', 20 }); + try expectError(error.InvalidByteSequence, null, &.{ 'a', '=', 'b', 128 }); + + try expectAttribute(.{ .name = "", .value = "a" }, null, "a"); + try expectAttribute(.{ .name = "", .value = "a" }, null, "a;"); + try expectAttribute(.{ .name = "", .value = "a b" }, null, "a b"); + try expectAttribute(.{ .name = "a b", .value = "b" }, null, "a b=b"); + try expectAttribute(.{ .name = "a,", .value = "b" }, null, "a,=b"); + try expectAttribute(.{ .name = ":a>", .value = "b>><" }, null, ":a>=b>><"); + + try expectAttribute(.{ .name = "abc", .value = "" }, null, "abc="); + try expectAttribute(.{ .name = "abc", .value = "" }, null, "abc=;"); + + try expectAttribute(.{ .name = "a", .value = "b" }, null, "a=b"); + try expectAttribute(.{ .name = "a", .value = "b" }, null, "a=b;"); + + try expectAttribute(.{ .name = "abc", .value = "fe f" }, null, "abc= fe f"); + try expectAttribute(.{ .name = "abc", .value = "fe f" }, null, "abc= fe f "); + try expectAttribute(.{ .name = "abc", .value = "fe f" }, null, "abc= fe f;"); + try expectAttribute(.{ .name = "abc", .value = "fe f" }, null, "abc= fe f ;"); + try expectAttribute(.{ .name = "abc", .value = "\" fe f\"" }, null, "abc=\" fe f\""); + try expectAttribute(.{ .name = "abc", .value = "\" fe f \"" }, null, "abc=\" fe f \""); + try expectAttribute(.{ .name = "ab4344c", .value = "1ads23" }, null, " ab4344c=1ads23 "); + + try expectAttribute(.{ .name = "ab4344c", .value = "1ads23" }, null, " ab4344c = 1ads23 ;"); +} + +test "Cookie: parse path" { + try expectAttribute(.{ .path = "/" }, "http://a/", "b"); + try expectAttribute(.{ .path = "/" }, "http://a/", "b;path"); + try expectAttribute(.{ .path = "/" }, "http://a/", "b;Path="); + try expectAttribute(.{ .path = "/" }, "http://a/", "b;Path=;"); + try expectAttribute(.{ .path = "/" }, "http://a/", "b; Path=other"); + try expectAttribute(.{ .path = "/" }, "http://a/23", "b; path=other "); + + try expectAttribute(.{ .path = "/" }, "http://a/abc", "b"); + try expectAttribute(.{ .path = "/abc" }, "http://a/abc/", "b"); + try expectAttribute(.{ .path = "/abc" }, "http://a/abc/123", "b"); + try expectAttribute(.{ .path = "/abc/123" }, "http://a/abc/123/", "b"); + + try expectAttribute(.{ .path = "/a" }, "http://a/", "b;Path=/a"); + try expectAttribute(.{ .path = "/aa" }, "http://a/", "b;path=/aa;"); + try expectAttribute(.{ .path = "/aabc/" }, "http://a/", "b; path= /aabc/ ;"); + + try expectAttribute(.{ .path = "/bbb/" }, "http://a/", "b; path=/a/; path=/bbb/"); + try expectAttribute(.{ .path = "/cc" }, "http://a/", "b; path=/a/; path=/bbb/; path = /cc"); +} + +test "Cookie: parse secure" { + try expectAttribute(.{ .secure = false }, null, "b"); + try expectAttribute(.{ .secure = false }, null, "b;secured"); + try expectAttribute(.{ .secure = false }, null, "b;security"); + try expectAttribute(.{ .secure = false }, null, "b;SecureX"); + try expectAttribute(.{ .secure = true }, null, "b; Secure"); + try expectAttribute(.{ .secure = true }, null, "b; Secure "); + try expectAttribute(.{ .secure = true }, null, "b; Secure=on "); + try expectAttribute(.{ .secure = true }, null, "b; Secure=Off "); + try expectAttribute(.{ .secure = true }, null, "b; secure=Off "); + try expectAttribute(.{ .secure = true }, null, "b; seCUre=Off "); +} + +test "Cookie: parse HttpOnly" { + try expectAttribute(.{ .http_only = false }, null, "b"); + try expectAttribute(.{ .http_only = false }, null, "b;HttpOnly0"); + try expectAttribute(.{ .http_only = false }, null, "b;H ttpOnly"); + try expectAttribute(.{ .http_only = true }, null, "b; HttpOnly"); + try expectAttribute(.{ .http_only = true }, null, "b; Httponly "); + try expectAttribute(.{ .http_only = true }, null, "b; Httponly=on "); + try expectAttribute(.{ .http_only = true }, null, "b; httpOnly=Off "); + try expectAttribute(.{ .http_only = true }, null, "b; httpOnly=Off "); + try expectAttribute(.{ .http_only = true }, null, "b; HttpOnly=Off "); +} + +test "Cookie: parse SameSite" { + try expectAttribute(.{ .same_site = .lax }, null, "b;samesite"); + try expectAttribute(.{ .same_site = .lax }, null, "b;samesite=lax"); + try expectAttribute(.{ .same_site = .lax }, null, "b; SameSite=Lax "); + try expectAttribute(.{ .same_site = .lax }, null, "b; SameSite=Other "); + try expectAttribute(.{ .same_site = .lax }, null, "b; SameSite=Nope "); + + // SameSite=none is only valid when Secure is set. The whole cookie is + // rejected otherwise + try expectError(error.InsecureSameSite, null, "b;samesite=none"); + try expectError(error.InsecureSameSite, null, "b;SameSite=None"); + try expectAttribute(.{ .same_site = .none }, null, "b; samesite=none; secure "); + try expectAttribute(.{ .same_site = .none }, null, "b; SameSite=None ; SECURE"); + try expectAttribute(.{ .same_site = .none }, null, "b;Secure; SameSite=None"); + try expectAttribute(.{ .same_site = .none }, null, "b; SameSite=None; Secure"); + + try expectAttribute(.{ .same_site = .strict }, null, "b; samesite=Strict "); + try expectAttribute(.{ .same_site = .strict }, null, "b; SameSite= STRICT "); + try expectAttribute(.{ .same_site = .strict }, null, "b; SameSITE=strict;"); + try expectAttribute(.{ .same_site = .strict }, null, "b; SameSite=Strict"); + + try expectAttribute(.{ .same_site = .strict }, null, "b; SameSite=None; SameSite=lax; SameSite=Strict"); +} + +test "Cookie: parse max-age" { + try expectAttribute(.{ .expires = null }, null, "b;max-age"); + try expectAttribute(.{ .expires = null }, null, "b;max-age=abc"); + try expectAttribute(.{ .expires = null }, null, "b;max-age=13.22"); + try expectAttribute(.{ .expires = null }, null, "b;max-age=13abc"); + + try expectAttribute(.{ .expires = std.time.timestamp() + 13 }, null, "b;max-age=13"); + try expectAttribute(.{ .expires = std.time.timestamp() + -22 }, null, "b;max-age=-22"); + try expectAttribute(.{ .expires = std.time.timestamp() + 4294967296 }, null, "b;max-age=4294967296"); + try expectAttribute(.{ .expires = std.time.timestamp() + -4294967296 }, null, "b;Max-Age= -4294967296"); + try expectAttribute(.{ .expires = std.time.timestamp() + 0 }, null, "b; Max-Age=0"); + try expectAttribute(.{ .expires = std.time.timestamp() + 500 }, null, "b; Max-Age = 500 ; Max-Age=invalid"); + try expectAttribute(.{ .expires = std.time.timestamp() + 1000 }, null, "b;max-age=600;max-age=0;max-age = 1000"); +} + +test "Cookie: parse expires" { + try expectAttribute(.{ .expires = null }, null, "b;expires="); + try expectAttribute(.{ .expires = null }, null, "b;expires=abc"); + try expectAttribute(.{ .expires = null }, null, "b;expires=13.22"); + try expectAttribute(.{ .expires = null }, null, "b;expires=33"); + + try expectAttribute(.{ .expires = 1918798080 - std.time.timestamp() }, null, "b;expires=Wed, 21 Oct 2030 07:28:00 GMT"); + // max-age has priority over expires + try expectAttribute(.{ .expires = std.time.timestamp() + 10 }, null, "b;Max-Age=10; expires=Wed, 21 Oct 2030 07:28:00 GMT"); +} + +test "Cookie: parse all" { + try expectCookie(.{ + .name = "user-id", + .value = "9000", + .path = "/cms", + .domain = "lightpanda.io", + }, "https://lightpanda.io/cms/users", "user-id=9000"); + + try expectCookie(.{ + .name = "user-id", + .value = "9000", + .path = "/", + .http_only = true, + .secure = true, + .domain = ".lightpanda.io", + .expires = std.time.timestamp() + 30, + }, "https://lightpanda.io/cms/users", "user-id=9000; HttpOnly; Max-Age=30; Secure; path=/; Domain=lightpanda.io"); +} + +test "Cookie: parse domain" { + try expectAttribute(.{ .domain = "lightpanda.io" }, "http://lightpanda.io/", "b"); + try expectAttribute(.{ .domain = "dev.lightpanda.io" }, "http://dev.lightpanda.io/", "b"); + try expectAttribute(.{ .domain = ".lightpanda.io" }, "http://lightpanda.io/", "b;domain=lightpanda.io"); + try expectAttribute(.{ .domain = ".lightpanda.io" }, "http://lightpanda.io/", "b;domain=.lightpanda.io"); + try expectAttribute(.{ .domain = ".dev.lightpanda.io" }, "http://dev.lightpanda.io/", "b;domain=dev.lightpanda.io"); + try expectAttribute(.{ .domain = ".lightpanda.io" }, "http://dev.lightpanda.io/", "b;domain=lightpanda.io"); + try expectAttribute(.{ .domain = ".lightpanda.io" }, "http://dev.lightpanda.io/", "b;domain=.lightpanda.io"); + + try expectError(error.InvalidDomain, "http://lightpanda.io/", "b;domain=io"); + try expectError(error.InvalidDomain, "http://lightpanda.io/", "b;domain=.io"); + try expectError(error.InvalidDomain, "http://lightpanda.io/", "b;domain=other.lightpanda.io"); + try expectError(error.InvalidDomain, "http://lightpanda.io/", "b;domain=other.lightpanda.com"); + try expectError(error.InvalidDomain, "http://lightpanda.io/", "b;domain=other.example.com"); +} + +const ExpectedCookie = struct { + name: []const u8, + value: []const u8, + path: []const u8, + domain: []const u8, + expires: ?i64 = null, + secure: bool = false, + http_only: bool = false, + same_site: Cookie.SameSite = .lax, +}; + +fn expectCookie(expected: ExpectedCookie, url: []const u8, set_cookie: []const u8) !void { + const uri = try Uri.parse(url); + var cookie = try Cookie.parse(testing.allocator, uri, set_cookie); + defer cookie.deinit(); + + try testing.expectEqual(expected.name, cookie.name); + try testing.expectEqual(expected.value, cookie.value); + try testing.expectEqual(expected.secure, cookie.secure); + try testing.expectEqual(expected.http_only, cookie.http_only); + try testing.expectEqual(expected.same_site, cookie.same_site); + try testing.expectEqual(expected.path, cookie.path); + try testing.expectEqual(expected.domain, cookie.domain); + + try testing.expectDelta(expected.expires, cookie.expires, 2); +} + +fn expectAttribute(expected: anytype, url: ?[]const u8, set_cookie: []const u8) !void { + const uri = if (url) |u| try Uri.parse(u) else test_uri; + var cookie = try Cookie.parse(testing.allocator, uri, set_cookie); + defer cookie.deinit(); + + inline for (@typeInfo(@TypeOf(expected)).Struct.fields) |f| { + if (comptime std.mem.eql(u8, f.name, "expires")) { + try testing.expectDelta(expected.expires, cookie.expires, 1); + } else { + try testing.expectEqual(@field(expected, f.name), @field(cookie, f.name)); + } + } +} + +fn expectError(expected: anyerror, url: ?[]const u8, set_cookie: []const u8) !void { + const uri = if (url) |u| try Uri.parse(u) else test_uri; + try testing.expectError(expected, Cookie.parse(testing.allocator, uri, set_cookie)); +} + +const test_uri = Uri.parse("http://lightpanda.io/") catch unreachable; diff --git a/src/testing.zig b/src/testing.zig new file mode 100644 index 00000000..f0b3f6e0 --- /dev/null +++ b/src/testing.zig @@ -0,0 +1,134 @@ +const std = @import("std"); + +pub const allocator = std.testing.allocator; +pub const expectError = std.testing.expectError; +pub const expectString = std.testing.expectEqualStrings; + +// Merged std.testing.expectEqual and std.testing.expectString +// can be useful when testing fields of an anytype an you don't know +// exactly how to assert equality +pub fn expectEqual(expected: anytype, actual: anytype) !void { + switch (@typeInfo(@TypeOf(actual))) { + .Array => |arr| if (arr.child == u8) { + return std.testing.expectEqualStrings(expected, &actual); + }, + .Pointer => |ptr| if (ptr.child == u8) { + return std.testing.expectEqualStrings(expected, actual); + } else if (comptime isStringArray(ptr.child)) { + return std.testing.expectEqualStrings(expected, actual); + } else if (ptr.child == []u8 or ptr.child == []const u8) { + return expectString(expected, actual); + }, + .Struct => |structType| { + inline for (structType.fields) |field| { + try expectEqual(@field(expected, field.name), @field(actual, field.name)); + } + return; + }, + .Optional => { + if (actual == null) { + return std.testing.expectEqual(null, expected); + } + return expectEqual(expected, actual.?); + }, + .Union => |union_info| { + if (union_info.tag_type == null) { + @compileError("Unable to compare untagged union values"); + } + const Tag = std.meta.Tag(@TypeOf(expected)); + + const expectedTag = @as(Tag, expected); + const actualTag = @as(Tag, actual); + try expectEqual(expectedTag, actualTag); + + inline for (std.meta.fields(@TypeOf(actual))) |fld| { + if (std.mem.eql(u8, fld.name, @tagName(actualTag))) { + try expectEqual(@field(expected, fld.name), @field(actual, fld.name)); + return; + } + } + unreachable; + }, + else => {}, + } + return std.testing.expectEqual(expected, actual); +} + +pub fn expectDelta(expected: anytype, actual: anytype, delta: anytype) !void { + if (@typeInfo(@TypeOf(expected)) == .Null) { + return std.testing.expectEqual(null, actual); + } + + switch (@typeInfo(@TypeOf(actual))) { + .Optional => { + if (actual) |value| { + return expectDelta(expected, value, delta); + } + return std.testing.expectEqual(null, expected); + }, + else => {}, + } + + switch (@typeInfo(@TypeOf(expected))) { + .Optional => { + if (expected) |value| { + return expectDelta(value, actual, delta); + } + return std.testing.expectEqual(null, actual); + }, + else => {}, + } + + var diff = expected - actual; + if (diff < 0) { + diff = -diff; + } + if (diff <= delta) { + return; + } + + print("Expected {} to be within {} of {}. Actual diff: {}", .{ expected, delta, actual, diff }); + return error.NotWithinDelta; +} + +fn isStringArray(comptime T: type) bool { + if (!is(.array)(T) and !isPtrTo(.array)(T)) { + return false; + } + return std.meta.Elem(T) == u8; +} + +pub const TraitFn = fn (type) bool; +pub fn is(comptime id: std.builtin.TypeId) TraitFn { + const Closure = struct { + pub fn trait(comptime T: type) bool { + return id == @typeInfo(T); + } + }; + return Closure.trait; +} + +pub fn isPtrTo(comptime id: std.builtin.TypeId) TraitFn { + const Closure = struct { + pub fn trait(comptime T: type) bool { + if (!comptime isSingleItemPtr(T)) return false; + return id == @typeInfo(std.meta.Child(T)); + } + }; + return Closure.trait; +} + +pub fn isSingleItemPtr(comptime T: type) bool { + if (comptime is(.pointer)(T)) { + return @typeInfo(T).Pointer.size == .one; + } + return false; +} + +pub fn print(comptime fmt: []const u8, args: anytype) void { + if (@inComptime()) { + @compileError(std.fmt.comptimePrint(fmt, args)); + } else { + std.debug.print(fmt, args); + } +} diff --git a/src/unit_tests.zig b/src/unit_tests.zig index 0aa70354..440a1f41 100644 --- a/src/unit_tests.zig +++ b/src/unit_tests.zig @@ -378,8 +378,10 @@ test { std.testing.refAllDecls(@import("generate.zig")); std.testing.refAllDecls(@import("http/Client.zig")); std.testing.refAllDecls(@import("storage/storage.zig")); + std.testing.refAllDecls(@import("storage/cookie.zig")); std.testing.refAllDecls(@import("iterator/iterator.zig")); std.testing.refAllDecls(@import("server.zig")); std.testing.refAllDecls(@import("cdp/cdp.zig")); std.testing.refAllDecls(@import("log.zig")); + std.testing.refAllDecls(@import("datetime.zig")); }