@email-utils/validator-syntax 0.0.1-9 → 1.0.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/Readme.md +1 -1
- package/THIRD_PARTY_NOTICES.md +37 -0
- package/dist/fixtures.cjs +2229 -0
- package/dist/fixtures.cjs.map +1 -0
- package/dist/fixtures.d.cts +247 -0
- package/dist/fixtures.d.mts +247 -0
- package/dist/fixtures.mjs +2220 -0
- package/dist/fixtures.mjs.map +1 -0
- package/dist/index.cjs +2310 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +96 -0
- package/dist/index.d.mts +96 -0
- package/dist/index.mjs +2307 -0
- package/dist/index.mjs.map +1 -0
- package/dist/result-CNbJ54oT.d.cts +116 -0
- package/dist/result-CNbJ54oT.d.mts +116 -0
- package/package.json +66 -73
- package/.babelrc +0 -8
- package/.eslintignore +0 -5
- package/.nvmrc +0 -1
- package/.nycrc.json +0 -11
- package/@types/index.d.ts +0 -30
- package/Readme.old.md +0 -103
- package/bin/tag.sh +0 -21
- package/dist/index.js +0 -272
- package/dist/index.js.map +0 -1
- package/src/index.ts +0 -342
- package/test/index.test.ts +0 -1612
- package/tsconfig.json +0 -22
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2310 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region src/chars.ts
|
|
3
|
+
const charCodeAt = String.prototype.charCodeAt;
|
|
4
|
+
/**
|
|
5
|
+
* `text.charCodeAt(i)`, through the builtin itself. Called as a method,
|
|
6
|
+
* `charCodeAt` is looked up on the string, and a call site that has seen
|
|
7
|
+
* enough kinds of string (one-byte and two-byte, flat, sliced, and
|
|
8
|
+
* concatenated) goes megamorphic: V8 stops inlining it, and after arbitrary
|
|
9
|
+
* Unicode input every scan ran 2–3× slower (validator-syntax#15).
|
|
10
|
+
*/
|
|
11
|
+
function codeAt(text, i) {
|
|
12
|
+
return charCodeAt.call(text, i);
|
|
13
|
+
}
|
|
14
|
+
const table = /* @__PURE__ */ new Uint8Array(128);
|
|
15
|
+
function mark(chars, flag) {
|
|
16
|
+
for (let i = 0; i < chars.length; i++) table[codeAt(chars, i)] |= flag;
|
|
17
|
+
}
|
|
18
|
+
const alnum = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
19
|
+
mark(alnum + "!#$%&'*+-/=?^_`{|}~", 1);
|
|
20
|
+
mark(alnum + "#$&'*+-/=?^_`{|}~", 2);
|
|
21
|
+
mark(alnum + "!#$%&'*+-/=?^_`{|}~.", 4);
|
|
22
|
+
mark(alnum + "-", 8);
|
|
23
|
+
/** Whether the character with this code is in the class `flag`. */
|
|
24
|
+
function inClass(code, flag) {
|
|
25
|
+
return code < 128 && (table[code] & flag) !== 0;
|
|
26
|
+
}
|
|
27
|
+
/** Space, tab, CR, and LF: the characters folding whitespace is made of. */
|
|
28
|
+
function isWhitespace(code) {
|
|
29
|
+
return code === 32 || code === 9 || code === 13 || code === 10;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The code units in the non-ASCII code point at `i`, before `end`: 2 for a
|
|
33
|
+
* surrogate pair, 1 for anything else outside ASCII, and 0 for ASCII or a
|
|
34
|
+
* lone surrogate, which no UTF-8 text can hold.
|
|
35
|
+
*/
|
|
36
|
+
function nonAsciiAt(text, i, end) {
|
|
37
|
+
const code = codeAt(text, i);
|
|
38
|
+
if (code < 128 || code >= 56320 && code <= 57343) return 0;
|
|
39
|
+
if (code < 55296 || code > 56319) return 1;
|
|
40
|
+
const low = i + 1 < end ? codeAt(text, i + 1) : 0;
|
|
41
|
+
return low >= 56320 && low <= 57343 ? 2 : 0;
|
|
42
|
+
}
|
|
43
|
+
/** The length of `text` in UTF-8 octets, the unit RFC 6531 caps a local part in. */
|
|
44
|
+
function utf8Length(text) {
|
|
45
|
+
const end = text.length;
|
|
46
|
+
let octets = end;
|
|
47
|
+
for (let i = 0; i < end; i++) {
|
|
48
|
+
const code = codeAt(text, i);
|
|
49
|
+
if (code >= 2048 && (code < 55296 || code > 57343)) octets += 2;
|
|
50
|
+
else if (code >= 128) octets += 1;
|
|
51
|
+
}
|
|
52
|
+
return octets;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The code points in `text` from `start` to `end`, which must not split a
|
|
56
|
+
* surrogate pair: its length with each pair counted once.
|
|
57
|
+
*/
|
|
58
|
+
function codePoints(text, start, end) {
|
|
59
|
+
let count = end - start;
|
|
60
|
+
for (let i = start; i < end; i++) {
|
|
61
|
+
const code = codeAt(text, i);
|
|
62
|
+
if (code >= 56320 && code <= 57343) count--;
|
|
63
|
+
}
|
|
64
|
+
return count;
|
|
65
|
+
}
|
|
66
|
+
//#endregion
|
|
67
|
+
//#region src/options.ts
|
|
68
|
+
const presets = {
|
|
69
|
+
practical: {
|
|
70
|
+
local: 2,
|
|
71
|
+
domain: 8,
|
|
72
|
+
quotes: false,
|
|
73
|
+
literals: false,
|
|
74
|
+
comments: false,
|
|
75
|
+
obs: false,
|
|
76
|
+
localCap: 64,
|
|
77
|
+
domainCap: 253,
|
|
78
|
+
checkTld: true,
|
|
79
|
+
allowNoTld: false,
|
|
80
|
+
unicode: false,
|
|
81
|
+
idn: false,
|
|
82
|
+
maxLength: 512
|
|
83
|
+
},
|
|
84
|
+
rfc5321: {
|
|
85
|
+
local: 1,
|
|
86
|
+
domain: 8,
|
|
87
|
+
quotes: true,
|
|
88
|
+
literals: true,
|
|
89
|
+
comments: false,
|
|
90
|
+
obs: false,
|
|
91
|
+
localCap: 64,
|
|
92
|
+
domainCap: 253,
|
|
93
|
+
checkTld: false,
|
|
94
|
+
allowNoTld: false,
|
|
95
|
+
unicode: false,
|
|
96
|
+
idn: false,
|
|
97
|
+
maxLength: 512
|
|
98
|
+
},
|
|
99
|
+
rfc5322: {
|
|
100
|
+
local: 1,
|
|
101
|
+
domain: 1,
|
|
102
|
+
quotes: true,
|
|
103
|
+
literals: true,
|
|
104
|
+
comments: true,
|
|
105
|
+
obs: true,
|
|
106
|
+
localCap: Infinity,
|
|
107
|
+
domainCap: 253,
|
|
108
|
+
checkTld: false,
|
|
109
|
+
allowNoTld: false,
|
|
110
|
+
unicode: false,
|
|
111
|
+
idn: false,
|
|
112
|
+
maxLength: 512
|
|
113
|
+
},
|
|
114
|
+
html5: {
|
|
115
|
+
local: 4,
|
|
116
|
+
domain: 8,
|
|
117
|
+
quotes: false,
|
|
118
|
+
literals: false,
|
|
119
|
+
comments: false,
|
|
120
|
+
obs: false,
|
|
121
|
+
localCap: Infinity,
|
|
122
|
+
domainCap: Infinity,
|
|
123
|
+
checkTld: false,
|
|
124
|
+
allowNoTld: true,
|
|
125
|
+
unicode: false,
|
|
126
|
+
idn: false,
|
|
127
|
+
maxLength: 512
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
const overrides = [
|
|
131
|
+
"checkTld",
|
|
132
|
+
"allowNoTld",
|
|
133
|
+
"allowComments",
|
|
134
|
+
"allowUnicode",
|
|
135
|
+
"allowIdn",
|
|
136
|
+
"allowIpLiteral"
|
|
137
|
+
];
|
|
138
|
+
const unsupported = {
|
|
139
|
+
practical: [],
|
|
140
|
+
rfc5321: ["allowComments"],
|
|
141
|
+
rfc5322: [],
|
|
142
|
+
html5: [
|
|
143
|
+
"allowComments",
|
|
144
|
+
"allowUnicode",
|
|
145
|
+
"allowIdn",
|
|
146
|
+
"allowIpLiteral"
|
|
147
|
+
]
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* Resolves `options` into the rules they select.
|
|
151
|
+
*
|
|
152
|
+
* @throws TypeError when `options` isn't an object, names an unknown option
|
|
153
|
+
* or preset, gives a non-boolean override or a `maxLength` that isn't a
|
|
154
|
+
* positive integer or `Infinity`, or turns on something the preset's grammar
|
|
155
|
+
* has no room for.
|
|
156
|
+
*/
|
|
157
|
+
function resolve(options) {
|
|
158
|
+
if (options === void 0) return presets.practical;
|
|
159
|
+
if (typeof options !== "object" || options === null) throw new TypeError("Expected the options to be an object");
|
|
160
|
+
for (const key of Object.keys(options)) if (key !== "preset" && key !== "maxLength" && !overrides.includes(key)) throw new TypeError(`Unknown option: ${key}`);
|
|
161
|
+
const preset = options.preset ?? "practical";
|
|
162
|
+
if (!Object.hasOwn(presets, preset)) throw new TypeError(`Unknown preset: ${preset}`);
|
|
163
|
+
const base = presets[preset];
|
|
164
|
+
for (const key of overrides) {
|
|
165
|
+
const value = options[key];
|
|
166
|
+
if (value !== void 0 && typeof value !== "boolean") throw new TypeError(`Expected ${key} to be a boolean`);
|
|
167
|
+
}
|
|
168
|
+
const { maxLength } = options;
|
|
169
|
+
if (maxLength !== void 0 && maxLength !== Infinity && !(Number.isInteger(maxLength) && maxLength > 0)) throw new TypeError("Expected maxLength to be a positive integer or Infinity");
|
|
170
|
+
for (const key of unsupported[preset]) if (options[key] === true) throw new TypeError(`${key} can’t be true with the ${preset} preset`);
|
|
171
|
+
if (maxLength === void 0 && overrides.every((key) => options[key] === void 0)) return base;
|
|
172
|
+
return {
|
|
173
|
+
...base,
|
|
174
|
+
checkTld: options.checkTld ?? base.checkTld,
|
|
175
|
+
allowNoTld: options.allowNoTld ?? base.allowNoTld,
|
|
176
|
+
comments: options.allowComments ?? base.comments,
|
|
177
|
+
unicode: options.allowUnicode ?? base.unicode,
|
|
178
|
+
idn: options.allowIdn ?? base.idn,
|
|
179
|
+
literals: options.allowIpLiteral ?? base.literals,
|
|
180
|
+
maxLength: maxLength ?? base.maxLength
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
//#endregion
|
|
184
|
+
//#region src/idn.ts
|
|
185
|
+
const ldh = /^[\da-z-]+$/;
|
|
186
|
+
/**
|
|
187
|
+
* The hostname of `http://x.` and `host`, or `undefined` when the WHATWG URL
|
|
188
|
+
* parser rejects it. `URL.parse` says so without the cost of throwing, a few
|
|
189
|
+
* µs a time, so an address built to fail many conversions stays fast;
|
|
190
|
+
* runtimes that predate it (Node before 22.1) throw instead.
|
|
191
|
+
*/
|
|
192
|
+
const hostnameOf = typeof URL.parse === "function" ? (host) => URL.parse(`http://x.${host}`)?.hostname : (host) => {
|
|
193
|
+
try {
|
|
194
|
+
return new URL(`http://x.${host}`).hostname;
|
|
195
|
+
} catch {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
/**
|
|
200
|
+
* The A-label for a U-label, or `undefined` when UTS #46 rejects it or maps
|
|
201
|
+
* it to something other than one IDN label (plain ASCII, or two labels, as
|
|
202
|
+
* `。` becomes a dot).
|
|
203
|
+
*
|
|
204
|
+
* @remarks
|
|
205
|
+
* Converts by way of the WHATWG URL host parser, which every runtime the
|
|
206
|
+
* package supports has and which applies UTS #46 with its bidi and joiner
|
|
207
|
+
* checks. It leaves hyphens and lengths alone, so the caller checks those.
|
|
208
|
+
*/
|
|
209
|
+
function toALabel(label) {
|
|
210
|
+
const aLabel = hostnameOf(label)?.slice(2);
|
|
211
|
+
return aLabel?.startsWith("xn--") === true && ldh.test(aLabel) ? aLabel : void 0;
|
|
212
|
+
}
|
|
213
|
+
const rtl = /[\u0590-\u08ff\u2135-\u2138\ufb1d-\ufdff\ufe70-\ufeff\u{10800}-\u{10fff}\u{1e800}-\u{1efff}]/u;
|
|
214
|
+
/**
|
|
215
|
+
* The A-label for each U-label in `labels`, as {@link toALabel} gives it,
|
|
216
|
+
* converted as few domains as it can: one URL costs about as much as one
|
|
217
|
+
* label does.
|
|
218
|
+
*
|
|
219
|
+
* @remarks
|
|
220
|
+
* Every entry up to the first `undefined` is exact; entries after it may be
|
|
221
|
+
* left `undefined` unconverted. Converted together, a right-to-left label
|
|
222
|
+
* would hold the others to RFC 5893's rules too, which it doesn't alone, so
|
|
223
|
+
* right-to-left labels go in a domain of their own. Converting more labels
|
|
224
|
+
* at once only adds rules, so a domain that converts means every label
|
|
225
|
+
* would alone; one that doesn't is narrowed down to its first label that
|
|
226
|
+
* fails alone.
|
|
227
|
+
*/
|
|
228
|
+
function toALabels(labels) {
|
|
229
|
+
if (!labels.some((label) => rtl.test(label))) return convertGroup(labels);
|
|
230
|
+
const aLabels = labels.map(() => void 0);
|
|
231
|
+
for (const bidi of [false, true]) {
|
|
232
|
+
const members = [];
|
|
233
|
+
labels.forEach((label, k) => {
|
|
234
|
+
if (rtl.test(label) === bidi) members.push(k);
|
|
235
|
+
});
|
|
236
|
+
if (members.length > 0) convertGroup(members.map((k) => labels[k])).forEach((aLabel, j) => {
|
|
237
|
+
aLabels[members[j]] = aLabel;
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
return aLabels;
|
|
241
|
+
}
|
|
242
|
+
/** {@link toALabels} for labels converted together. */
|
|
243
|
+
function convertGroup(labels) {
|
|
244
|
+
const all = convert(labels);
|
|
245
|
+
if (all !== void 0) return all;
|
|
246
|
+
let pass = [];
|
|
247
|
+
let failing = labels.length;
|
|
248
|
+
while (failing - pass.length > 1) {
|
|
249
|
+
const some = convert(labels.slice(0, pass.length + failing >> 1));
|
|
250
|
+
if (some === void 0) failing = pass.length + failing >> 1;
|
|
251
|
+
else pass = some;
|
|
252
|
+
}
|
|
253
|
+
const aLabels = pass;
|
|
254
|
+
for (let k = pass.length; k < labels.length; k++) {
|
|
255
|
+
const aLabel = toALabel(labels[k]);
|
|
256
|
+
aLabels.push(aLabel);
|
|
257
|
+
if (aLabel === void 0) break;
|
|
258
|
+
}
|
|
259
|
+
return aLabels;
|
|
260
|
+
}
|
|
261
|
+
const aLabelHost = /^x(?:\.xn--[\da-z-]+)+$/;
|
|
262
|
+
/** `labels` converted as one domain, or `undefined`. */
|
|
263
|
+
function convert(labels) {
|
|
264
|
+
const hostname = hostnameOf(labels.join("."));
|
|
265
|
+
if (hostname === void 0 || !aLabelHost.test(hostname)) return;
|
|
266
|
+
const aLabels = hostname.split(".");
|
|
267
|
+
aLabels.shift();
|
|
268
|
+
return aLabels.length === labels.length ? aLabels : void 0;
|
|
269
|
+
}
|
|
270
|
+
//#endregion
|
|
271
|
+
//#region src/ip.ts
|
|
272
|
+
const octet = /^\d{1,3}$/;
|
|
273
|
+
const hexGroup = /^[\dA-Fa-f]{1,4}$/;
|
|
274
|
+
/** An IPv4 address: four dot-separated decimal octets, each 0–255. */
|
|
275
|
+
function isIPv4(text) {
|
|
276
|
+
if (text.length > 15) return false;
|
|
277
|
+
const parts = text.split(".");
|
|
278
|
+
return parts.length === 4 && parts.every((part) => octet.test(part) && Number(part) <= 255);
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* An IPv6 address as RFC 5321 writes it: eight hex groups, or a `::` with no
|
|
282
|
+
* more than six groups beside it, and either may end in an IPv4 address in
|
|
283
|
+
* place of the last two groups.
|
|
284
|
+
*/
|
|
285
|
+
function isIPv6(text) {
|
|
286
|
+
if (text.length > 45) return false;
|
|
287
|
+
const colon = text.lastIndexOf(":");
|
|
288
|
+
const tail = text.slice(colon + 1);
|
|
289
|
+
if (tail.includes(".")) {
|
|
290
|
+
if (!isIPv4(tail)) return false;
|
|
291
|
+
text = `${text.slice(0, colon + 1)}0:0`;
|
|
292
|
+
}
|
|
293
|
+
const halves = text.split("::");
|
|
294
|
+
if (halves.length > 2) return false;
|
|
295
|
+
const groups = halves.flatMap((half) => half === "" ? [] : half.split(":"));
|
|
296
|
+
return groups.every((group) => hexGroup.test(group)) && (halves.length === 1 ? groups.length === 8 : groups.length <= 6);
|
|
297
|
+
}
|
|
298
|
+
/** The text of an RFC 5321 address literal: IPv4, or `IPv6:` and IPv6. */
|
|
299
|
+
function isAddressLiteral(text) {
|
|
300
|
+
return /^IPv6:/i.test(text) ? isIPv6(text.slice(5)) : isIPv4(text);
|
|
301
|
+
}
|
|
302
|
+
//#endregion
|
|
303
|
+
//#region node_modules/tlds/index.json
|
|
304
|
+
var tlds_default = [
|
|
305
|
+
"aaa",
|
|
306
|
+
"aarp",
|
|
307
|
+
"abb",
|
|
308
|
+
"abbott",
|
|
309
|
+
"abbvie",
|
|
310
|
+
"abc",
|
|
311
|
+
"able",
|
|
312
|
+
"abogado",
|
|
313
|
+
"abudhabi",
|
|
314
|
+
"ac",
|
|
315
|
+
"academy",
|
|
316
|
+
"accenture",
|
|
317
|
+
"accountant",
|
|
318
|
+
"accountants",
|
|
319
|
+
"aco",
|
|
320
|
+
"actor",
|
|
321
|
+
"ad",
|
|
322
|
+
"ads",
|
|
323
|
+
"adult",
|
|
324
|
+
"ae",
|
|
325
|
+
"aeg",
|
|
326
|
+
"aero",
|
|
327
|
+
"aetna",
|
|
328
|
+
"af",
|
|
329
|
+
"afl",
|
|
330
|
+
"africa",
|
|
331
|
+
"ag",
|
|
332
|
+
"agakhan",
|
|
333
|
+
"agency",
|
|
334
|
+
"ai",
|
|
335
|
+
"aig",
|
|
336
|
+
"airbus",
|
|
337
|
+
"airforce",
|
|
338
|
+
"airtel",
|
|
339
|
+
"akdn",
|
|
340
|
+
"al",
|
|
341
|
+
"alibaba",
|
|
342
|
+
"alipay",
|
|
343
|
+
"allfinanz",
|
|
344
|
+
"allstate",
|
|
345
|
+
"ally",
|
|
346
|
+
"alsace",
|
|
347
|
+
"alstom",
|
|
348
|
+
"am",
|
|
349
|
+
"amazon",
|
|
350
|
+
"americanexpress",
|
|
351
|
+
"americanfamily",
|
|
352
|
+
"amex",
|
|
353
|
+
"amfam",
|
|
354
|
+
"amica",
|
|
355
|
+
"amsterdam",
|
|
356
|
+
"analytics",
|
|
357
|
+
"android",
|
|
358
|
+
"anquan",
|
|
359
|
+
"anz",
|
|
360
|
+
"ao",
|
|
361
|
+
"aol",
|
|
362
|
+
"apartments",
|
|
363
|
+
"app",
|
|
364
|
+
"apple",
|
|
365
|
+
"aq",
|
|
366
|
+
"aquarelle",
|
|
367
|
+
"ar",
|
|
368
|
+
"arab",
|
|
369
|
+
"aramco",
|
|
370
|
+
"archi",
|
|
371
|
+
"army",
|
|
372
|
+
"arpa",
|
|
373
|
+
"art",
|
|
374
|
+
"arte",
|
|
375
|
+
"as",
|
|
376
|
+
"asda",
|
|
377
|
+
"asia",
|
|
378
|
+
"associates",
|
|
379
|
+
"at",
|
|
380
|
+
"athleta",
|
|
381
|
+
"attorney",
|
|
382
|
+
"au",
|
|
383
|
+
"auction",
|
|
384
|
+
"audi",
|
|
385
|
+
"audible",
|
|
386
|
+
"audio",
|
|
387
|
+
"auspost",
|
|
388
|
+
"author",
|
|
389
|
+
"auto",
|
|
390
|
+
"autos",
|
|
391
|
+
"aw",
|
|
392
|
+
"aws",
|
|
393
|
+
"ax",
|
|
394
|
+
"axa",
|
|
395
|
+
"az",
|
|
396
|
+
"azure",
|
|
397
|
+
"ba",
|
|
398
|
+
"baby",
|
|
399
|
+
"baidu",
|
|
400
|
+
"banamex",
|
|
401
|
+
"band",
|
|
402
|
+
"bank",
|
|
403
|
+
"bar",
|
|
404
|
+
"barcelona",
|
|
405
|
+
"barclaycard",
|
|
406
|
+
"barclays",
|
|
407
|
+
"barefoot",
|
|
408
|
+
"bargains",
|
|
409
|
+
"baseball",
|
|
410
|
+
"basketball",
|
|
411
|
+
"bauhaus",
|
|
412
|
+
"bayern",
|
|
413
|
+
"bb",
|
|
414
|
+
"bbc",
|
|
415
|
+
"bbt",
|
|
416
|
+
"bbva",
|
|
417
|
+
"bcg",
|
|
418
|
+
"bcn",
|
|
419
|
+
"bd",
|
|
420
|
+
"be",
|
|
421
|
+
"beats",
|
|
422
|
+
"beauty",
|
|
423
|
+
"beer",
|
|
424
|
+
"berlin",
|
|
425
|
+
"best",
|
|
426
|
+
"bestbuy",
|
|
427
|
+
"bet",
|
|
428
|
+
"bf",
|
|
429
|
+
"bg",
|
|
430
|
+
"bh",
|
|
431
|
+
"bharti",
|
|
432
|
+
"bi",
|
|
433
|
+
"bible",
|
|
434
|
+
"bid",
|
|
435
|
+
"bike",
|
|
436
|
+
"bing",
|
|
437
|
+
"bingo",
|
|
438
|
+
"bio",
|
|
439
|
+
"biz",
|
|
440
|
+
"bj",
|
|
441
|
+
"black",
|
|
442
|
+
"blackfriday",
|
|
443
|
+
"blockbuster",
|
|
444
|
+
"blog",
|
|
445
|
+
"bloomberg",
|
|
446
|
+
"blue",
|
|
447
|
+
"bm",
|
|
448
|
+
"bms",
|
|
449
|
+
"bmw",
|
|
450
|
+
"bn",
|
|
451
|
+
"bnpparibas",
|
|
452
|
+
"bo",
|
|
453
|
+
"boats",
|
|
454
|
+
"boehringer",
|
|
455
|
+
"bofa",
|
|
456
|
+
"bom",
|
|
457
|
+
"bond",
|
|
458
|
+
"boo",
|
|
459
|
+
"book",
|
|
460
|
+
"booking",
|
|
461
|
+
"bosch",
|
|
462
|
+
"bostik",
|
|
463
|
+
"boston",
|
|
464
|
+
"bot",
|
|
465
|
+
"boutique",
|
|
466
|
+
"box",
|
|
467
|
+
"br",
|
|
468
|
+
"bradesco",
|
|
469
|
+
"bridgestone",
|
|
470
|
+
"broadway",
|
|
471
|
+
"broker",
|
|
472
|
+
"brother",
|
|
473
|
+
"brussels",
|
|
474
|
+
"bs",
|
|
475
|
+
"bt",
|
|
476
|
+
"build",
|
|
477
|
+
"builders",
|
|
478
|
+
"business",
|
|
479
|
+
"buy",
|
|
480
|
+
"buzz",
|
|
481
|
+
"bv",
|
|
482
|
+
"bw",
|
|
483
|
+
"by",
|
|
484
|
+
"bz",
|
|
485
|
+
"bzh",
|
|
486
|
+
"ca",
|
|
487
|
+
"cab",
|
|
488
|
+
"cafe",
|
|
489
|
+
"cal",
|
|
490
|
+
"call",
|
|
491
|
+
"calvinklein",
|
|
492
|
+
"cam",
|
|
493
|
+
"camera",
|
|
494
|
+
"camp",
|
|
495
|
+
"canon",
|
|
496
|
+
"capetown",
|
|
497
|
+
"capital",
|
|
498
|
+
"capitalone",
|
|
499
|
+
"car",
|
|
500
|
+
"caravan",
|
|
501
|
+
"cards",
|
|
502
|
+
"care",
|
|
503
|
+
"career",
|
|
504
|
+
"careers",
|
|
505
|
+
"cars",
|
|
506
|
+
"casa",
|
|
507
|
+
"case",
|
|
508
|
+
"cash",
|
|
509
|
+
"casino",
|
|
510
|
+
"cat",
|
|
511
|
+
"catering",
|
|
512
|
+
"catholic",
|
|
513
|
+
"cba",
|
|
514
|
+
"cbn",
|
|
515
|
+
"cbre",
|
|
516
|
+
"cc",
|
|
517
|
+
"cd",
|
|
518
|
+
"center",
|
|
519
|
+
"ceo",
|
|
520
|
+
"cern",
|
|
521
|
+
"cf",
|
|
522
|
+
"cfa",
|
|
523
|
+
"cfd",
|
|
524
|
+
"cg",
|
|
525
|
+
"ch",
|
|
526
|
+
"chanel",
|
|
527
|
+
"channel",
|
|
528
|
+
"charity",
|
|
529
|
+
"chase",
|
|
530
|
+
"chat",
|
|
531
|
+
"cheap",
|
|
532
|
+
"chintai",
|
|
533
|
+
"christmas",
|
|
534
|
+
"chrome",
|
|
535
|
+
"church",
|
|
536
|
+
"ci",
|
|
537
|
+
"cipriani",
|
|
538
|
+
"circle",
|
|
539
|
+
"cisco",
|
|
540
|
+
"citadel",
|
|
541
|
+
"citi",
|
|
542
|
+
"citic",
|
|
543
|
+
"city",
|
|
544
|
+
"ck",
|
|
545
|
+
"cl",
|
|
546
|
+
"claims",
|
|
547
|
+
"cleaning",
|
|
548
|
+
"click",
|
|
549
|
+
"clinic",
|
|
550
|
+
"clinique",
|
|
551
|
+
"clothing",
|
|
552
|
+
"cloud",
|
|
553
|
+
"club",
|
|
554
|
+
"clubmed",
|
|
555
|
+
"cm",
|
|
556
|
+
"cn",
|
|
557
|
+
"co",
|
|
558
|
+
"coach",
|
|
559
|
+
"codes",
|
|
560
|
+
"coffee",
|
|
561
|
+
"college",
|
|
562
|
+
"cologne",
|
|
563
|
+
"com",
|
|
564
|
+
"commbank",
|
|
565
|
+
"community",
|
|
566
|
+
"company",
|
|
567
|
+
"compare",
|
|
568
|
+
"computer",
|
|
569
|
+
"comsec",
|
|
570
|
+
"condos",
|
|
571
|
+
"construction",
|
|
572
|
+
"consulting",
|
|
573
|
+
"contact",
|
|
574
|
+
"contractors",
|
|
575
|
+
"cooking",
|
|
576
|
+
"cool",
|
|
577
|
+
"coop",
|
|
578
|
+
"corsica",
|
|
579
|
+
"country",
|
|
580
|
+
"coupon",
|
|
581
|
+
"coupons",
|
|
582
|
+
"courses",
|
|
583
|
+
"cpa",
|
|
584
|
+
"cr",
|
|
585
|
+
"credit",
|
|
586
|
+
"creditcard",
|
|
587
|
+
"creditunion",
|
|
588
|
+
"cricket",
|
|
589
|
+
"crown",
|
|
590
|
+
"crs",
|
|
591
|
+
"cruise",
|
|
592
|
+
"cruises",
|
|
593
|
+
"cu",
|
|
594
|
+
"cuisinella",
|
|
595
|
+
"cv",
|
|
596
|
+
"cw",
|
|
597
|
+
"cx",
|
|
598
|
+
"cy",
|
|
599
|
+
"cymru",
|
|
600
|
+
"cyou",
|
|
601
|
+
"cz",
|
|
602
|
+
"dad",
|
|
603
|
+
"dance",
|
|
604
|
+
"data",
|
|
605
|
+
"date",
|
|
606
|
+
"dating",
|
|
607
|
+
"datsun",
|
|
608
|
+
"day",
|
|
609
|
+
"dclk",
|
|
610
|
+
"dds",
|
|
611
|
+
"de",
|
|
612
|
+
"deal",
|
|
613
|
+
"dealer",
|
|
614
|
+
"deals",
|
|
615
|
+
"degree",
|
|
616
|
+
"delivery",
|
|
617
|
+
"dell",
|
|
618
|
+
"deloitte",
|
|
619
|
+
"delta",
|
|
620
|
+
"democrat",
|
|
621
|
+
"dental",
|
|
622
|
+
"dentist",
|
|
623
|
+
"desi",
|
|
624
|
+
"design",
|
|
625
|
+
"dev",
|
|
626
|
+
"dhl",
|
|
627
|
+
"diamonds",
|
|
628
|
+
"diet",
|
|
629
|
+
"digital",
|
|
630
|
+
"direct",
|
|
631
|
+
"directory",
|
|
632
|
+
"discount",
|
|
633
|
+
"discover",
|
|
634
|
+
"dish",
|
|
635
|
+
"diy",
|
|
636
|
+
"dj",
|
|
637
|
+
"dk",
|
|
638
|
+
"dm",
|
|
639
|
+
"dnp",
|
|
640
|
+
"do",
|
|
641
|
+
"docs",
|
|
642
|
+
"doctor",
|
|
643
|
+
"dog",
|
|
644
|
+
"domains",
|
|
645
|
+
"dot",
|
|
646
|
+
"download",
|
|
647
|
+
"drive",
|
|
648
|
+
"dtv",
|
|
649
|
+
"dubai",
|
|
650
|
+
"dupont",
|
|
651
|
+
"durban",
|
|
652
|
+
"dvag",
|
|
653
|
+
"dvr",
|
|
654
|
+
"dz",
|
|
655
|
+
"earth",
|
|
656
|
+
"eat",
|
|
657
|
+
"ec",
|
|
658
|
+
"eco",
|
|
659
|
+
"edeka",
|
|
660
|
+
"edu",
|
|
661
|
+
"education",
|
|
662
|
+
"ee",
|
|
663
|
+
"eg",
|
|
664
|
+
"email",
|
|
665
|
+
"emerck",
|
|
666
|
+
"energy",
|
|
667
|
+
"engineer",
|
|
668
|
+
"engineering",
|
|
669
|
+
"enterprises",
|
|
670
|
+
"epson",
|
|
671
|
+
"equipment",
|
|
672
|
+
"er",
|
|
673
|
+
"ericsson",
|
|
674
|
+
"erni",
|
|
675
|
+
"es",
|
|
676
|
+
"esq",
|
|
677
|
+
"estate",
|
|
678
|
+
"et",
|
|
679
|
+
"eu",
|
|
680
|
+
"eurovision",
|
|
681
|
+
"eus",
|
|
682
|
+
"events",
|
|
683
|
+
"exchange",
|
|
684
|
+
"expert",
|
|
685
|
+
"exposed",
|
|
686
|
+
"express",
|
|
687
|
+
"extraspace",
|
|
688
|
+
"fage",
|
|
689
|
+
"fail",
|
|
690
|
+
"fairwinds",
|
|
691
|
+
"faith",
|
|
692
|
+
"family",
|
|
693
|
+
"fan",
|
|
694
|
+
"fans",
|
|
695
|
+
"farm",
|
|
696
|
+
"farmers",
|
|
697
|
+
"fashion",
|
|
698
|
+
"fast",
|
|
699
|
+
"fedex",
|
|
700
|
+
"feedback",
|
|
701
|
+
"ferrari",
|
|
702
|
+
"ferrero",
|
|
703
|
+
"fi",
|
|
704
|
+
"fidelity",
|
|
705
|
+
"fido",
|
|
706
|
+
"film",
|
|
707
|
+
"final",
|
|
708
|
+
"finance",
|
|
709
|
+
"financial",
|
|
710
|
+
"fire",
|
|
711
|
+
"firestone",
|
|
712
|
+
"firmdale",
|
|
713
|
+
"fish",
|
|
714
|
+
"fishing",
|
|
715
|
+
"fit",
|
|
716
|
+
"fitness",
|
|
717
|
+
"fj",
|
|
718
|
+
"fk",
|
|
719
|
+
"flickr",
|
|
720
|
+
"flights",
|
|
721
|
+
"flir",
|
|
722
|
+
"florist",
|
|
723
|
+
"flowers",
|
|
724
|
+
"fly",
|
|
725
|
+
"fm",
|
|
726
|
+
"fo",
|
|
727
|
+
"foo",
|
|
728
|
+
"food",
|
|
729
|
+
"football",
|
|
730
|
+
"ford",
|
|
731
|
+
"forex",
|
|
732
|
+
"forsale",
|
|
733
|
+
"forum",
|
|
734
|
+
"foundation",
|
|
735
|
+
"fox",
|
|
736
|
+
"fr",
|
|
737
|
+
"free",
|
|
738
|
+
"fresenius",
|
|
739
|
+
"frl",
|
|
740
|
+
"frogans",
|
|
741
|
+
"frontier",
|
|
742
|
+
"ftr",
|
|
743
|
+
"fujitsu",
|
|
744
|
+
"fun",
|
|
745
|
+
"fund",
|
|
746
|
+
"furniture",
|
|
747
|
+
"futbol",
|
|
748
|
+
"fyi",
|
|
749
|
+
"ga",
|
|
750
|
+
"gal",
|
|
751
|
+
"gallery",
|
|
752
|
+
"gallo",
|
|
753
|
+
"gallup",
|
|
754
|
+
"game",
|
|
755
|
+
"games",
|
|
756
|
+
"gap",
|
|
757
|
+
"garden",
|
|
758
|
+
"gay",
|
|
759
|
+
"gb",
|
|
760
|
+
"gbiz",
|
|
761
|
+
"gd",
|
|
762
|
+
"gdn",
|
|
763
|
+
"ge",
|
|
764
|
+
"gea",
|
|
765
|
+
"gent",
|
|
766
|
+
"genting",
|
|
767
|
+
"george",
|
|
768
|
+
"gf",
|
|
769
|
+
"gg",
|
|
770
|
+
"ggee",
|
|
771
|
+
"gh",
|
|
772
|
+
"gi",
|
|
773
|
+
"gift",
|
|
774
|
+
"gifts",
|
|
775
|
+
"gives",
|
|
776
|
+
"giving",
|
|
777
|
+
"gl",
|
|
778
|
+
"glass",
|
|
779
|
+
"gle",
|
|
780
|
+
"global",
|
|
781
|
+
"globo",
|
|
782
|
+
"gm",
|
|
783
|
+
"gmail",
|
|
784
|
+
"gmbh",
|
|
785
|
+
"gmo",
|
|
786
|
+
"gmx",
|
|
787
|
+
"gn",
|
|
788
|
+
"godaddy",
|
|
789
|
+
"gold",
|
|
790
|
+
"goldpoint",
|
|
791
|
+
"golf",
|
|
792
|
+
"goo",
|
|
793
|
+
"goodyear",
|
|
794
|
+
"goog",
|
|
795
|
+
"google",
|
|
796
|
+
"gop",
|
|
797
|
+
"got",
|
|
798
|
+
"gov",
|
|
799
|
+
"gp",
|
|
800
|
+
"gq",
|
|
801
|
+
"gr",
|
|
802
|
+
"grainger",
|
|
803
|
+
"graphics",
|
|
804
|
+
"gratis",
|
|
805
|
+
"green",
|
|
806
|
+
"gripe",
|
|
807
|
+
"grocery",
|
|
808
|
+
"group",
|
|
809
|
+
"gs",
|
|
810
|
+
"gt",
|
|
811
|
+
"gu",
|
|
812
|
+
"gucci",
|
|
813
|
+
"guge",
|
|
814
|
+
"guide",
|
|
815
|
+
"guitars",
|
|
816
|
+
"guru",
|
|
817
|
+
"gw",
|
|
818
|
+
"gy",
|
|
819
|
+
"hair",
|
|
820
|
+
"hamburg",
|
|
821
|
+
"hangout",
|
|
822
|
+
"haus",
|
|
823
|
+
"hbo",
|
|
824
|
+
"hdfc",
|
|
825
|
+
"hdfcbank",
|
|
826
|
+
"health",
|
|
827
|
+
"healthcare",
|
|
828
|
+
"help",
|
|
829
|
+
"helsinki",
|
|
830
|
+
"here",
|
|
831
|
+
"hermes",
|
|
832
|
+
"hiphop",
|
|
833
|
+
"hisamitsu",
|
|
834
|
+
"hitachi",
|
|
835
|
+
"hiv",
|
|
836
|
+
"hk",
|
|
837
|
+
"hkt",
|
|
838
|
+
"hm",
|
|
839
|
+
"hn",
|
|
840
|
+
"hockey",
|
|
841
|
+
"holdings",
|
|
842
|
+
"holiday",
|
|
843
|
+
"homedepot",
|
|
844
|
+
"homegoods",
|
|
845
|
+
"homes",
|
|
846
|
+
"homesense",
|
|
847
|
+
"honda",
|
|
848
|
+
"horse",
|
|
849
|
+
"hospital",
|
|
850
|
+
"host",
|
|
851
|
+
"hosting",
|
|
852
|
+
"hot",
|
|
853
|
+
"hotels",
|
|
854
|
+
"hotmail",
|
|
855
|
+
"house",
|
|
856
|
+
"how",
|
|
857
|
+
"hr",
|
|
858
|
+
"hsbc",
|
|
859
|
+
"ht",
|
|
860
|
+
"hu",
|
|
861
|
+
"hughes",
|
|
862
|
+
"hyatt",
|
|
863
|
+
"hyundai",
|
|
864
|
+
"ibm",
|
|
865
|
+
"icbc",
|
|
866
|
+
"ice",
|
|
867
|
+
"icu",
|
|
868
|
+
"id",
|
|
869
|
+
"ie",
|
|
870
|
+
"ieee",
|
|
871
|
+
"ifm",
|
|
872
|
+
"ikano",
|
|
873
|
+
"il",
|
|
874
|
+
"im",
|
|
875
|
+
"imamat",
|
|
876
|
+
"imdb",
|
|
877
|
+
"immo",
|
|
878
|
+
"immobilien",
|
|
879
|
+
"in",
|
|
880
|
+
"inc",
|
|
881
|
+
"industries",
|
|
882
|
+
"infiniti",
|
|
883
|
+
"info",
|
|
884
|
+
"ing",
|
|
885
|
+
"ink",
|
|
886
|
+
"institute",
|
|
887
|
+
"insurance",
|
|
888
|
+
"insure",
|
|
889
|
+
"int",
|
|
890
|
+
"international",
|
|
891
|
+
"intuit",
|
|
892
|
+
"investments",
|
|
893
|
+
"io",
|
|
894
|
+
"ipiranga",
|
|
895
|
+
"iq",
|
|
896
|
+
"ir",
|
|
897
|
+
"irish",
|
|
898
|
+
"is",
|
|
899
|
+
"ismaili",
|
|
900
|
+
"ist",
|
|
901
|
+
"istanbul",
|
|
902
|
+
"it",
|
|
903
|
+
"itau",
|
|
904
|
+
"itv",
|
|
905
|
+
"jaguar",
|
|
906
|
+
"java",
|
|
907
|
+
"jcb",
|
|
908
|
+
"je",
|
|
909
|
+
"jeep",
|
|
910
|
+
"jetzt",
|
|
911
|
+
"jewelry",
|
|
912
|
+
"jio",
|
|
913
|
+
"jll",
|
|
914
|
+
"jm",
|
|
915
|
+
"jmp",
|
|
916
|
+
"jnj",
|
|
917
|
+
"jo",
|
|
918
|
+
"jobs",
|
|
919
|
+
"joburg",
|
|
920
|
+
"jot",
|
|
921
|
+
"joy",
|
|
922
|
+
"jp",
|
|
923
|
+
"jpmorgan",
|
|
924
|
+
"jprs",
|
|
925
|
+
"juegos",
|
|
926
|
+
"juniper",
|
|
927
|
+
"kaufen",
|
|
928
|
+
"kddi",
|
|
929
|
+
"ke",
|
|
930
|
+
"kerryhotels",
|
|
931
|
+
"kerryproperties",
|
|
932
|
+
"kfh",
|
|
933
|
+
"kg",
|
|
934
|
+
"kh",
|
|
935
|
+
"ki",
|
|
936
|
+
"kia",
|
|
937
|
+
"kids",
|
|
938
|
+
"kim",
|
|
939
|
+
"kindle",
|
|
940
|
+
"kitchen",
|
|
941
|
+
"kiwi",
|
|
942
|
+
"km",
|
|
943
|
+
"kn",
|
|
944
|
+
"koeln",
|
|
945
|
+
"komatsu",
|
|
946
|
+
"kosher",
|
|
947
|
+
"kp",
|
|
948
|
+
"kpmg",
|
|
949
|
+
"kpn",
|
|
950
|
+
"kr",
|
|
951
|
+
"krd",
|
|
952
|
+
"kred",
|
|
953
|
+
"kuokgroup",
|
|
954
|
+
"kw",
|
|
955
|
+
"ky",
|
|
956
|
+
"kyoto",
|
|
957
|
+
"kz",
|
|
958
|
+
"la",
|
|
959
|
+
"lacaixa",
|
|
960
|
+
"lamborghini",
|
|
961
|
+
"lamer",
|
|
962
|
+
"land",
|
|
963
|
+
"landrover",
|
|
964
|
+
"lanxess",
|
|
965
|
+
"lasalle",
|
|
966
|
+
"lat",
|
|
967
|
+
"latino",
|
|
968
|
+
"latrobe",
|
|
969
|
+
"law",
|
|
970
|
+
"lawyer",
|
|
971
|
+
"lb",
|
|
972
|
+
"lc",
|
|
973
|
+
"lds",
|
|
974
|
+
"lease",
|
|
975
|
+
"leclerc",
|
|
976
|
+
"lefrak",
|
|
977
|
+
"legal",
|
|
978
|
+
"lego",
|
|
979
|
+
"lexus",
|
|
980
|
+
"lgbt",
|
|
981
|
+
"li",
|
|
982
|
+
"lidl",
|
|
983
|
+
"life",
|
|
984
|
+
"lifeinsurance",
|
|
985
|
+
"lifestyle",
|
|
986
|
+
"lighting",
|
|
987
|
+
"like",
|
|
988
|
+
"lilly",
|
|
989
|
+
"limited",
|
|
990
|
+
"limo",
|
|
991
|
+
"lincoln",
|
|
992
|
+
"link",
|
|
993
|
+
"live",
|
|
994
|
+
"living",
|
|
995
|
+
"lk",
|
|
996
|
+
"llc",
|
|
997
|
+
"llp",
|
|
998
|
+
"loan",
|
|
999
|
+
"loans",
|
|
1000
|
+
"locker",
|
|
1001
|
+
"locus",
|
|
1002
|
+
"lol",
|
|
1003
|
+
"london",
|
|
1004
|
+
"lotte",
|
|
1005
|
+
"lotto",
|
|
1006
|
+
"love",
|
|
1007
|
+
"lpl",
|
|
1008
|
+
"lplfinancial",
|
|
1009
|
+
"lr",
|
|
1010
|
+
"ls",
|
|
1011
|
+
"lt",
|
|
1012
|
+
"ltd",
|
|
1013
|
+
"ltda",
|
|
1014
|
+
"lu",
|
|
1015
|
+
"lundbeck",
|
|
1016
|
+
"luxe",
|
|
1017
|
+
"luxury",
|
|
1018
|
+
"lv",
|
|
1019
|
+
"ly",
|
|
1020
|
+
"ma",
|
|
1021
|
+
"madrid",
|
|
1022
|
+
"maif",
|
|
1023
|
+
"maison",
|
|
1024
|
+
"makeup",
|
|
1025
|
+
"man",
|
|
1026
|
+
"management",
|
|
1027
|
+
"mango",
|
|
1028
|
+
"map",
|
|
1029
|
+
"market",
|
|
1030
|
+
"marketing",
|
|
1031
|
+
"markets",
|
|
1032
|
+
"marriott",
|
|
1033
|
+
"marshalls",
|
|
1034
|
+
"mattel",
|
|
1035
|
+
"mba",
|
|
1036
|
+
"mc",
|
|
1037
|
+
"mckinsey",
|
|
1038
|
+
"md",
|
|
1039
|
+
"me",
|
|
1040
|
+
"med",
|
|
1041
|
+
"media",
|
|
1042
|
+
"meet",
|
|
1043
|
+
"melbourne",
|
|
1044
|
+
"meme",
|
|
1045
|
+
"memorial",
|
|
1046
|
+
"men",
|
|
1047
|
+
"menu",
|
|
1048
|
+
"merckmsd",
|
|
1049
|
+
"mg",
|
|
1050
|
+
"mh",
|
|
1051
|
+
"miami",
|
|
1052
|
+
"microsoft",
|
|
1053
|
+
"mil",
|
|
1054
|
+
"mini",
|
|
1055
|
+
"mint",
|
|
1056
|
+
"mit",
|
|
1057
|
+
"mitsubishi",
|
|
1058
|
+
"mk",
|
|
1059
|
+
"ml",
|
|
1060
|
+
"mlb",
|
|
1061
|
+
"mls",
|
|
1062
|
+
"mm",
|
|
1063
|
+
"mma",
|
|
1064
|
+
"mn",
|
|
1065
|
+
"mo",
|
|
1066
|
+
"mobi",
|
|
1067
|
+
"mobile",
|
|
1068
|
+
"moda",
|
|
1069
|
+
"moe",
|
|
1070
|
+
"moi",
|
|
1071
|
+
"mom",
|
|
1072
|
+
"monash",
|
|
1073
|
+
"money",
|
|
1074
|
+
"monster",
|
|
1075
|
+
"mormon",
|
|
1076
|
+
"mortgage",
|
|
1077
|
+
"moscow",
|
|
1078
|
+
"moto",
|
|
1079
|
+
"motorcycles",
|
|
1080
|
+
"mov",
|
|
1081
|
+
"movie",
|
|
1082
|
+
"mp",
|
|
1083
|
+
"mq",
|
|
1084
|
+
"mr",
|
|
1085
|
+
"ms",
|
|
1086
|
+
"msd",
|
|
1087
|
+
"mt",
|
|
1088
|
+
"mtn",
|
|
1089
|
+
"mtr",
|
|
1090
|
+
"mu",
|
|
1091
|
+
"museum",
|
|
1092
|
+
"music",
|
|
1093
|
+
"mv",
|
|
1094
|
+
"mw",
|
|
1095
|
+
"mx",
|
|
1096
|
+
"my",
|
|
1097
|
+
"mz",
|
|
1098
|
+
"na",
|
|
1099
|
+
"nab",
|
|
1100
|
+
"nagoya",
|
|
1101
|
+
"name",
|
|
1102
|
+
"navy",
|
|
1103
|
+
"nba",
|
|
1104
|
+
"nc",
|
|
1105
|
+
"ne",
|
|
1106
|
+
"nec",
|
|
1107
|
+
"net",
|
|
1108
|
+
"netbank",
|
|
1109
|
+
"netflix",
|
|
1110
|
+
"network",
|
|
1111
|
+
"neustar",
|
|
1112
|
+
"new",
|
|
1113
|
+
"news",
|
|
1114
|
+
"next",
|
|
1115
|
+
"nextdirect",
|
|
1116
|
+
"nexus",
|
|
1117
|
+
"nf",
|
|
1118
|
+
"nfl",
|
|
1119
|
+
"ng",
|
|
1120
|
+
"ngo",
|
|
1121
|
+
"nhk",
|
|
1122
|
+
"ni",
|
|
1123
|
+
"nico",
|
|
1124
|
+
"nike",
|
|
1125
|
+
"nikon",
|
|
1126
|
+
"ninja",
|
|
1127
|
+
"nissan",
|
|
1128
|
+
"nissay",
|
|
1129
|
+
"nl",
|
|
1130
|
+
"no",
|
|
1131
|
+
"nokia",
|
|
1132
|
+
"norton",
|
|
1133
|
+
"now",
|
|
1134
|
+
"nowruz",
|
|
1135
|
+
"nowtv",
|
|
1136
|
+
"np",
|
|
1137
|
+
"nr",
|
|
1138
|
+
"nra",
|
|
1139
|
+
"nrw",
|
|
1140
|
+
"ntt",
|
|
1141
|
+
"nu",
|
|
1142
|
+
"nyc",
|
|
1143
|
+
"nz",
|
|
1144
|
+
"obi",
|
|
1145
|
+
"observer",
|
|
1146
|
+
"office",
|
|
1147
|
+
"okinawa",
|
|
1148
|
+
"olayan",
|
|
1149
|
+
"olayangroup",
|
|
1150
|
+
"ollo",
|
|
1151
|
+
"om",
|
|
1152
|
+
"omega",
|
|
1153
|
+
"one",
|
|
1154
|
+
"ong",
|
|
1155
|
+
"onl",
|
|
1156
|
+
"online",
|
|
1157
|
+
"ooo",
|
|
1158
|
+
"open",
|
|
1159
|
+
"oracle",
|
|
1160
|
+
"orange",
|
|
1161
|
+
"org",
|
|
1162
|
+
"organic",
|
|
1163
|
+
"origins",
|
|
1164
|
+
"osaka",
|
|
1165
|
+
"otsuka",
|
|
1166
|
+
"ott",
|
|
1167
|
+
"ovh",
|
|
1168
|
+
"pa",
|
|
1169
|
+
"page",
|
|
1170
|
+
"panasonic",
|
|
1171
|
+
"paris",
|
|
1172
|
+
"pars",
|
|
1173
|
+
"partners",
|
|
1174
|
+
"parts",
|
|
1175
|
+
"party",
|
|
1176
|
+
"pay",
|
|
1177
|
+
"pccw",
|
|
1178
|
+
"pe",
|
|
1179
|
+
"pet",
|
|
1180
|
+
"pf",
|
|
1181
|
+
"pfizer",
|
|
1182
|
+
"pg",
|
|
1183
|
+
"ph",
|
|
1184
|
+
"pharmacy",
|
|
1185
|
+
"phd",
|
|
1186
|
+
"philips",
|
|
1187
|
+
"phone",
|
|
1188
|
+
"photo",
|
|
1189
|
+
"photography",
|
|
1190
|
+
"photos",
|
|
1191
|
+
"physio",
|
|
1192
|
+
"pics",
|
|
1193
|
+
"pictet",
|
|
1194
|
+
"pictures",
|
|
1195
|
+
"pid",
|
|
1196
|
+
"pin",
|
|
1197
|
+
"ping",
|
|
1198
|
+
"pink",
|
|
1199
|
+
"pioneer",
|
|
1200
|
+
"pizza",
|
|
1201
|
+
"pk",
|
|
1202
|
+
"pl",
|
|
1203
|
+
"place",
|
|
1204
|
+
"play",
|
|
1205
|
+
"playstation",
|
|
1206
|
+
"plumbing",
|
|
1207
|
+
"plus",
|
|
1208
|
+
"pm",
|
|
1209
|
+
"pn",
|
|
1210
|
+
"pnc",
|
|
1211
|
+
"pohl",
|
|
1212
|
+
"poker",
|
|
1213
|
+
"politie",
|
|
1214
|
+
"porn",
|
|
1215
|
+
"post",
|
|
1216
|
+
"pr",
|
|
1217
|
+
"praxi",
|
|
1218
|
+
"press",
|
|
1219
|
+
"prime",
|
|
1220
|
+
"pro",
|
|
1221
|
+
"prod",
|
|
1222
|
+
"productions",
|
|
1223
|
+
"prof",
|
|
1224
|
+
"progressive",
|
|
1225
|
+
"promo",
|
|
1226
|
+
"properties",
|
|
1227
|
+
"property",
|
|
1228
|
+
"protection",
|
|
1229
|
+
"pru",
|
|
1230
|
+
"prudential",
|
|
1231
|
+
"ps",
|
|
1232
|
+
"pt",
|
|
1233
|
+
"pub",
|
|
1234
|
+
"pw",
|
|
1235
|
+
"pwc",
|
|
1236
|
+
"py",
|
|
1237
|
+
"qa",
|
|
1238
|
+
"qpon",
|
|
1239
|
+
"quebec",
|
|
1240
|
+
"quest",
|
|
1241
|
+
"racing",
|
|
1242
|
+
"radio",
|
|
1243
|
+
"re",
|
|
1244
|
+
"read",
|
|
1245
|
+
"realestate",
|
|
1246
|
+
"realtor",
|
|
1247
|
+
"realty",
|
|
1248
|
+
"recipes",
|
|
1249
|
+
"red",
|
|
1250
|
+
"redumbrella",
|
|
1251
|
+
"rehab",
|
|
1252
|
+
"reise",
|
|
1253
|
+
"reisen",
|
|
1254
|
+
"reit",
|
|
1255
|
+
"reliance",
|
|
1256
|
+
"ren",
|
|
1257
|
+
"rent",
|
|
1258
|
+
"rentals",
|
|
1259
|
+
"repair",
|
|
1260
|
+
"report",
|
|
1261
|
+
"republican",
|
|
1262
|
+
"rest",
|
|
1263
|
+
"restaurant",
|
|
1264
|
+
"review",
|
|
1265
|
+
"reviews",
|
|
1266
|
+
"rexroth",
|
|
1267
|
+
"rich",
|
|
1268
|
+
"richardli",
|
|
1269
|
+
"ricoh",
|
|
1270
|
+
"ril",
|
|
1271
|
+
"rio",
|
|
1272
|
+
"rip",
|
|
1273
|
+
"ro",
|
|
1274
|
+
"rocks",
|
|
1275
|
+
"rodeo",
|
|
1276
|
+
"rogers",
|
|
1277
|
+
"room",
|
|
1278
|
+
"rs",
|
|
1279
|
+
"rsvp",
|
|
1280
|
+
"ru",
|
|
1281
|
+
"rugby",
|
|
1282
|
+
"ruhr",
|
|
1283
|
+
"run",
|
|
1284
|
+
"rw",
|
|
1285
|
+
"rwe",
|
|
1286
|
+
"ryukyu",
|
|
1287
|
+
"sa",
|
|
1288
|
+
"saarland",
|
|
1289
|
+
"safe",
|
|
1290
|
+
"safety",
|
|
1291
|
+
"sakura",
|
|
1292
|
+
"sale",
|
|
1293
|
+
"salon",
|
|
1294
|
+
"samsclub",
|
|
1295
|
+
"samsung",
|
|
1296
|
+
"sandvik",
|
|
1297
|
+
"sandvikcoromant",
|
|
1298
|
+
"sanofi",
|
|
1299
|
+
"sap",
|
|
1300
|
+
"sarl",
|
|
1301
|
+
"sas",
|
|
1302
|
+
"save",
|
|
1303
|
+
"saxo",
|
|
1304
|
+
"sb",
|
|
1305
|
+
"sbi",
|
|
1306
|
+
"sbs",
|
|
1307
|
+
"sc",
|
|
1308
|
+
"scb",
|
|
1309
|
+
"schaeffler",
|
|
1310
|
+
"schmidt",
|
|
1311
|
+
"scholarships",
|
|
1312
|
+
"school",
|
|
1313
|
+
"schule",
|
|
1314
|
+
"schwarz",
|
|
1315
|
+
"science",
|
|
1316
|
+
"scot",
|
|
1317
|
+
"sd",
|
|
1318
|
+
"se",
|
|
1319
|
+
"search",
|
|
1320
|
+
"seat",
|
|
1321
|
+
"secure",
|
|
1322
|
+
"security",
|
|
1323
|
+
"seek",
|
|
1324
|
+
"select",
|
|
1325
|
+
"sener",
|
|
1326
|
+
"services",
|
|
1327
|
+
"seven",
|
|
1328
|
+
"sew",
|
|
1329
|
+
"sex",
|
|
1330
|
+
"sexy",
|
|
1331
|
+
"sfr",
|
|
1332
|
+
"sg",
|
|
1333
|
+
"sh",
|
|
1334
|
+
"shangrila",
|
|
1335
|
+
"sharp",
|
|
1336
|
+
"shell",
|
|
1337
|
+
"shia",
|
|
1338
|
+
"shiksha",
|
|
1339
|
+
"shoes",
|
|
1340
|
+
"shop",
|
|
1341
|
+
"shopping",
|
|
1342
|
+
"shouji",
|
|
1343
|
+
"show",
|
|
1344
|
+
"si",
|
|
1345
|
+
"silk",
|
|
1346
|
+
"sina",
|
|
1347
|
+
"singles",
|
|
1348
|
+
"site",
|
|
1349
|
+
"sj",
|
|
1350
|
+
"sk",
|
|
1351
|
+
"ski",
|
|
1352
|
+
"skin",
|
|
1353
|
+
"sky",
|
|
1354
|
+
"skype",
|
|
1355
|
+
"sl",
|
|
1356
|
+
"sling",
|
|
1357
|
+
"sm",
|
|
1358
|
+
"smart",
|
|
1359
|
+
"smile",
|
|
1360
|
+
"sn",
|
|
1361
|
+
"sncf",
|
|
1362
|
+
"so",
|
|
1363
|
+
"soccer",
|
|
1364
|
+
"social",
|
|
1365
|
+
"softbank",
|
|
1366
|
+
"software",
|
|
1367
|
+
"sohu",
|
|
1368
|
+
"solar",
|
|
1369
|
+
"solutions",
|
|
1370
|
+
"song",
|
|
1371
|
+
"sony",
|
|
1372
|
+
"soy",
|
|
1373
|
+
"spa",
|
|
1374
|
+
"space",
|
|
1375
|
+
"sport",
|
|
1376
|
+
"spot",
|
|
1377
|
+
"sr",
|
|
1378
|
+
"srl",
|
|
1379
|
+
"ss",
|
|
1380
|
+
"st",
|
|
1381
|
+
"stada",
|
|
1382
|
+
"staples",
|
|
1383
|
+
"star",
|
|
1384
|
+
"statebank",
|
|
1385
|
+
"statefarm",
|
|
1386
|
+
"stc",
|
|
1387
|
+
"stcgroup",
|
|
1388
|
+
"stockholm",
|
|
1389
|
+
"storage",
|
|
1390
|
+
"store",
|
|
1391
|
+
"stream",
|
|
1392
|
+
"studio",
|
|
1393
|
+
"study",
|
|
1394
|
+
"style",
|
|
1395
|
+
"su",
|
|
1396
|
+
"sucks",
|
|
1397
|
+
"supplies",
|
|
1398
|
+
"supply",
|
|
1399
|
+
"support",
|
|
1400
|
+
"surf",
|
|
1401
|
+
"surgery",
|
|
1402
|
+
"suzuki",
|
|
1403
|
+
"sv",
|
|
1404
|
+
"swatch",
|
|
1405
|
+
"swiss",
|
|
1406
|
+
"sx",
|
|
1407
|
+
"sy",
|
|
1408
|
+
"sydney",
|
|
1409
|
+
"systems",
|
|
1410
|
+
"sz",
|
|
1411
|
+
"tab",
|
|
1412
|
+
"taipei",
|
|
1413
|
+
"talk",
|
|
1414
|
+
"taobao",
|
|
1415
|
+
"target",
|
|
1416
|
+
"tatamotors",
|
|
1417
|
+
"tatar",
|
|
1418
|
+
"tattoo",
|
|
1419
|
+
"tax",
|
|
1420
|
+
"taxi",
|
|
1421
|
+
"tc",
|
|
1422
|
+
"tci",
|
|
1423
|
+
"td",
|
|
1424
|
+
"tdk",
|
|
1425
|
+
"team",
|
|
1426
|
+
"tech",
|
|
1427
|
+
"technology",
|
|
1428
|
+
"tel",
|
|
1429
|
+
"temasek",
|
|
1430
|
+
"tennis",
|
|
1431
|
+
"teva",
|
|
1432
|
+
"tf",
|
|
1433
|
+
"tg",
|
|
1434
|
+
"th",
|
|
1435
|
+
"thd",
|
|
1436
|
+
"theater",
|
|
1437
|
+
"theatre",
|
|
1438
|
+
"tiaa",
|
|
1439
|
+
"tickets",
|
|
1440
|
+
"tienda",
|
|
1441
|
+
"tips",
|
|
1442
|
+
"tires",
|
|
1443
|
+
"tirol",
|
|
1444
|
+
"tj",
|
|
1445
|
+
"tjmaxx",
|
|
1446
|
+
"tjx",
|
|
1447
|
+
"tk",
|
|
1448
|
+
"tkmaxx",
|
|
1449
|
+
"tl",
|
|
1450
|
+
"tm",
|
|
1451
|
+
"tmall",
|
|
1452
|
+
"tn",
|
|
1453
|
+
"to",
|
|
1454
|
+
"today",
|
|
1455
|
+
"tokyo",
|
|
1456
|
+
"tools",
|
|
1457
|
+
"top",
|
|
1458
|
+
"toray",
|
|
1459
|
+
"toshiba",
|
|
1460
|
+
"total",
|
|
1461
|
+
"tours",
|
|
1462
|
+
"town",
|
|
1463
|
+
"toyota",
|
|
1464
|
+
"toys",
|
|
1465
|
+
"tr",
|
|
1466
|
+
"trade",
|
|
1467
|
+
"trading",
|
|
1468
|
+
"training",
|
|
1469
|
+
"travel",
|
|
1470
|
+
"travelers",
|
|
1471
|
+
"travelersinsurance",
|
|
1472
|
+
"trust",
|
|
1473
|
+
"trv",
|
|
1474
|
+
"tt",
|
|
1475
|
+
"tube",
|
|
1476
|
+
"tui",
|
|
1477
|
+
"tunes",
|
|
1478
|
+
"tushu",
|
|
1479
|
+
"tv",
|
|
1480
|
+
"tvs",
|
|
1481
|
+
"tw",
|
|
1482
|
+
"tz",
|
|
1483
|
+
"ua",
|
|
1484
|
+
"ubank",
|
|
1485
|
+
"ubs",
|
|
1486
|
+
"ug",
|
|
1487
|
+
"uk",
|
|
1488
|
+
"unicom",
|
|
1489
|
+
"university",
|
|
1490
|
+
"uno",
|
|
1491
|
+
"uol",
|
|
1492
|
+
"ups",
|
|
1493
|
+
"us",
|
|
1494
|
+
"uy",
|
|
1495
|
+
"uz",
|
|
1496
|
+
"va",
|
|
1497
|
+
"vacations",
|
|
1498
|
+
"vana",
|
|
1499
|
+
"vanguard",
|
|
1500
|
+
"vc",
|
|
1501
|
+
"ve",
|
|
1502
|
+
"vegas",
|
|
1503
|
+
"ventures",
|
|
1504
|
+
"verisign",
|
|
1505
|
+
"vermögensberater",
|
|
1506
|
+
"vermögensberatung",
|
|
1507
|
+
"versicherung",
|
|
1508
|
+
"vet",
|
|
1509
|
+
"vg",
|
|
1510
|
+
"vi",
|
|
1511
|
+
"viajes",
|
|
1512
|
+
"video",
|
|
1513
|
+
"vig",
|
|
1514
|
+
"viking",
|
|
1515
|
+
"villas",
|
|
1516
|
+
"vin",
|
|
1517
|
+
"vip",
|
|
1518
|
+
"virgin",
|
|
1519
|
+
"visa",
|
|
1520
|
+
"vision",
|
|
1521
|
+
"viva",
|
|
1522
|
+
"vivo",
|
|
1523
|
+
"vlaanderen",
|
|
1524
|
+
"vn",
|
|
1525
|
+
"vodka",
|
|
1526
|
+
"volvo",
|
|
1527
|
+
"vote",
|
|
1528
|
+
"voting",
|
|
1529
|
+
"voto",
|
|
1530
|
+
"voyage",
|
|
1531
|
+
"vu",
|
|
1532
|
+
"wales",
|
|
1533
|
+
"walmart",
|
|
1534
|
+
"walter",
|
|
1535
|
+
"wang",
|
|
1536
|
+
"wanggou",
|
|
1537
|
+
"watch",
|
|
1538
|
+
"watches",
|
|
1539
|
+
"weather",
|
|
1540
|
+
"weatherchannel",
|
|
1541
|
+
"webcam",
|
|
1542
|
+
"weber",
|
|
1543
|
+
"website",
|
|
1544
|
+
"wed",
|
|
1545
|
+
"wedding",
|
|
1546
|
+
"weibo",
|
|
1547
|
+
"weir",
|
|
1548
|
+
"wf",
|
|
1549
|
+
"whoswho",
|
|
1550
|
+
"wien",
|
|
1551
|
+
"wiki",
|
|
1552
|
+
"williamhill",
|
|
1553
|
+
"win",
|
|
1554
|
+
"windows",
|
|
1555
|
+
"wine",
|
|
1556
|
+
"winners",
|
|
1557
|
+
"wme",
|
|
1558
|
+
"wolterskluwer",
|
|
1559
|
+
"woodside",
|
|
1560
|
+
"work",
|
|
1561
|
+
"works",
|
|
1562
|
+
"world",
|
|
1563
|
+
"wow",
|
|
1564
|
+
"ws",
|
|
1565
|
+
"wtc",
|
|
1566
|
+
"wtf",
|
|
1567
|
+
"xbox",
|
|
1568
|
+
"xerox",
|
|
1569
|
+
"xihuan",
|
|
1570
|
+
"xin",
|
|
1571
|
+
"xxx",
|
|
1572
|
+
"xyz",
|
|
1573
|
+
"yachts",
|
|
1574
|
+
"yahoo",
|
|
1575
|
+
"yamaxun",
|
|
1576
|
+
"yandex",
|
|
1577
|
+
"ye",
|
|
1578
|
+
"yodobashi",
|
|
1579
|
+
"yoga",
|
|
1580
|
+
"yokohama",
|
|
1581
|
+
"you",
|
|
1582
|
+
"youtube",
|
|
1583
|
+
"yt",
|
|
1584
|
+
"yun",
|
|
1585
|
+
"za",
|
|
1586
|
+
"zappos",
|
|
1587
|
+
"zara",
|
|
1588
|
+
"zero",
|
|
1589
|
+
"zip",
|
|
1590
|
+
"zm",
|
|
1591
|
+
"zone",
|
|
1592
|
+
"zuerich",
|
|
1593
|
+
"zw",
|
|
1594
|
+
"ελ",
|
|
1595
|
+
"ευ",
|
|
1596
|
+
"бг",
|
|
1597
|
+
"бел",
|
|
1598
|
+
"дети",
|
|
1599
|
+
"ею",
|
|
1600
|
+
"католик",
|
|
1601
|
+
"ком",
|
|
1602
|
+
"мкд",
|
|
1603
|
+
"мон",
|
|
1604
|
+
"москва",
|
|
1605
|
+
"онлайн",
|
|
1606
|
+
"орг",
|
|
1607
|
+
"рус",
|
|
1608
|
+
"рф",
|
|
1609
|
+
"сайт",
|
|
1610
|
+
"срб",
|
|
1611
|
+
"укр",
|
|
1612
|
+
"қаз",
|
|
1613
|
+
"հայ",
|
|
1614
|
+
"ישראל",
|
|
1615
|
+
"קום",
|
|
1616
|
+
"ابوظبي",
|
|
1617
|
+
"ارامكو",
|
|
1618
|
+
"الاردن",
|
|
1619
|
+
"البحرين",
|
|
1620
|
+
"الجزائر",
|
|
1621
|
+
"السعودية",
|
|
1622
|
+
"العليان",
|
|
1623
|
+
"المغرب",
|
|
1624
|
+
"امارات",
|
|
1625
|
+
"ایران",
|
|
1626
|
+
"بارت",
|
|
1627
|
+
"بازار",
|
|
1628
|
+
"بيتك",
|
|
1629
|
+
"بھارت",
|
|
1630
|
+
"تونس",
|
|
1631
|
+
"سودان",
|
|
1632
|
+
"سورية",
|
|
1633
|
+
"شبكة",
|
|
1634
|
+
"عراق",
|
|
1635
|
+
"عرب",
|
|
1636
|
+
"عمان",
|
|
1637
|
+
"فلسطين",
|
|
1638
|
+
"قطر",
|
|
1639
|
+
"كاثوليك",
|
|
1640
|
+
"كوم",
|
|
1641
|
+
"مصر",
|
|
1642
|
+
"مليسيا",
|
|
1643
|
+
"موريتانيا",
|
|
1644
|
+
"موقع",
|
|
1645
|
+
"همراه",
|
|
1646
|
+
"پاکستان",
|
|
1647
|
+
"ڀارت",
|
|
1648
|
+
"कॉम",
|
|
1649
|
+
"नेट",
|
|
1650
|
+
"भारत",
|
|
1651
|
+
"भारतम्",
|
|
1652
|
+
"भारोत",
|
|
1653
|
+
"संगठन",
|
|
1654
|
+
"বাংলা",
|
|
1655
|
+
"ভারত",
|
|
1656
|
+
"ভাৰত",
|
|
1657
|
+
"ਭਾਰਤ",
|
|
1658
|
+
"ભારત",
|
|
1659
|
+
"ଭାରତ",
|
|
1660
|
+
"இந்தியா",
|
|
1661
|
+
"இலங்கை",
|
|
1662
|
+
"சிங்கப்பூர்",
|
|
1663
|
+
"భారత్",
|
|
1664
|
+
"ಭಾರತ",
|
|
1665
|
+
"ഭാരതം",
|
|
1666
|
+
"ලංකා",
|
|
1667
|
+
"คอม",
|
|
1668
|
+
"ไทย",
|
|
1669
|
+
"ລາວ",
|
|
1670
|
+
"გე",
|
|
1671
|
+
"みんな",
|
|
1672
|
+
"アマゾン",
|
|
1673
|
+
"クラウド",
|
|
1674
|
+
"グーグル",
|
|
1675
|
+
"コム",
|
|
1676
|
+
"ストア",
|
|
1677
|
+
"セール",
|
|
1678
|
+
"ファッション",
|
|
1679
|
+
"ポイント",
|
|
1680
|
+
"世界",
|
|
1681
|
+
"中信",
|
|
1682
|
+
"中国",
|
|
1683
|
+
"中國",
|
|
1684
|
+
"中文网",
|
|
1685
|
+
"亚马逊",
|
|
1686
|
+
"企业",
|
|
1687
|
+
"佛山",
|
|
1688
|
+
"信息",
|
|
1689
|
+
"健康",
|
|
1690
|
+
"八卦",
|
|
1691
|
+
"公司",
|
|
1692
|
+
"公益",
|
|
1693
|
+
"台湾",
|
|
1694
|
+
"台灣",
|
|
1695
|
+
"商城",
|
|
1696
|
+
"商店",
|
|
1697
|
+
"商标",
|
|
1698
|
+
"嘉里",
|
|
1699
|
+
"嘉里大酒店",
|
|
1700
|
+
"在线",
|
|
1701
|
+
"大拿",
|
|
1702
|
+
"天主教",
|
|
1703
|
+
"娱乐",
|
|
1704
|
+
"家電",
|
|
1705
|
+
"广东",
|
|
1706
|
+
"微博",
|
|
1707
|
+
"慈善",
|
|
1708
|
+
"我爱你",
|
|
1709
|
+
"手机",
|
|
1710
|
+
"招聘",
|
|
1711
|
+
"政务",
|
|
1712
|
+
"政府",
|
|
1713
|
+
"新加坡",
|
|
1714
|
+
"新闻",
|
|
1715
|
+
"时尚",
|
|
1716
|
+
"書籍",
|
|
1717
|
+
"机构",
|
|
1718
|
+
"淡马锡",
|
|
1719
|
+
"游戏",
|
|
1720
|
+
"澳門",
|
|
1721
|
+
"点看",
|
|
1722
|
+
"移动",
|
|
1723
|
+
"组织机构",
|
|
1724
|
+
"网址",
|
|
1725
|
+
"网店",
|
|
1726
|
+
"网站",
|
|
1727
|
+
"网络",
|
|
1728
|
+
"联通",
|
|
1729
|
+
"谷歌",
|
|
1730
|
+
"购物",
|
|
1731
|
+
"通販",
|
|
1732
|
+
"集团",
|
|
1733
|
+
"電訊盈科",
|
|
1734
|
+
"飞利浦",
|
|
1735
|
+
"食品",
|
|
1736
|
+
"餐厅",
|
|
1737
|
+
"香格里拉",
|
|
1738
|
+
"香港",
|
|
1739
|
+
"닷넷",
|
|
1740
|
+
"닷컴",
|
|
1741
|
+
"삼성",
|
|
1742
|
+
"한국"
|
|
1743
|
+
];
|
|
1744
|
+
//#endregion
|
|
1745
|
+
//#region src/tld.ts
|
|
1746
|
+
let known;
|
|
1747
|
+
/** Whether `tld` is in the IANA set, as a U-label or A-label, ignoring case. */
|
|
1748
|
+
function isKnownTld(tld) {
|
|
1749
|
+
known ??= buildSet();
|
|
1750
|
+
return known.has(tld.toLowerCase());
|
|
1751
|
+
}
|
|
1752
|
+
function buildSet() {
|
|
1753
|
+
const set = new Set(tlds_default);
|
|
1754
|
+
for (const tld of tlds_default) if (!/^[a-z\d]+$/.test(tld)) {
|
|
1755
|
+
const aLabel = toALabel(tld);
|
|
1756
|
+
if (aLabel !== void 0) set.add(aLabel);
|
|
1757
|
+
}
|
|
1758
|
+
return set;
|
|
1759
|
+
}
|
|
1760
|
+
//#endregion
|
|
1761
|
+
//#region src/parse.ts
|
|
1762
|
+
const messages = {
|
|
1763
|
+
"syntax.address.empty": "The address is empty",
|
|
1764
|
+
"syntax.address.no_at": "The address has no @",
|
|
1765
|
+
"syntax.address.too_long": "The address is longer than 254 characters",
|
|
1766
|
+
"syntax.local.empty": "Nothing comes before the @",
|
|
1767
|
+
"syntax.local.too_long": "The local part is longer than 64 characters",
|
|
1768
|
+
"syntax.local.invalid_char": "The local part has a character it can’t hold",
|
|
1769
|
+
"syntax.local.consecutive_dots": "The local part has two dots in a row",
|
|
1770
|
+
"syntax.local.unquoted_space": "The local part has whitespace outside quotes",
|
|
1771
|
+
"syntax.domain.empty": "Nothing comes after the @",
|
|
1772
|
+
"syntax.domain.no_dot": "The domain has no dot",
|
|
1773
|
+
"syntax.domain.label_invalid": "A domain label is empty, too long, or starts or ends with a hyphen",
|
|
1774
|
+
"syntax.domain.literal_invalid": "The domain literal isn’t accepted",
|
|
1775
|
+
"syntax.domain.too_long": "The domain is longer than 253 characters",
|
|
1776
|
+
"syntax.domain.invalid_char": "The domain has a character it can’t hold",
|
|
1777
|
+
"syntax.comment.not_allowed": "Comments aren’t allowed here",
|
|
1778
|
+
"syntax.comment.unterminated": "A comment is missing its closing parenthesis",
|
|
1779
|
+
"syntax.tld.unknown": "The TLD isn’t in the IANA set"
|
|
1780
|
+
};
|
|
1781
|
+
function fail(reason, index) {
|
|
1782
|
+
const message = messages[reason];
|
|
1783
|
+
return index === void 0 ? {
|
|
1784
|
+
ok: false,
|
|
1785
|
+
reason,
|
|
1786
|
+
message
|
|
1787
|
+
} : {
|
|
1788
|
+
ok: false,
|
|
1789
|
+
reason,
|
|
1790
|
+
message,
|
|
1791
|
+
index
|
|
1792
|
+
};
|
|
1793
|
+
}
|
|
1794
|
+
const NORMAL = 0;
|
|
1795
|
+
const QUOTED = 1;
|
|
1796
|
+
const COMMENT = 2;
|
|
1797
|
+
const LITERAL = 3;
|
|
1798
|
+
/**
|
|
1799
|
+
* Finds the `@` that splits `email`: the last one outside a quoted string,
|
|
1800
|
+
* comment, or domain literal, or -1 when there's none.
|
|
1801
|
+
*
|
|
1802
|
+
* @remarks
|
|
1803
|
+
* A quoted string opens only at the start of a word, and a literal only at
|
|
1804
|
+
* the start of the domain; both, and comments, take backslash escapes. One
|
|
1805
|
+
* left open runs to the end, taking any `@` with it.
|
|
1806
|
+
*/
|
|
1807
|
+
function findAt(email, rules) {
|
|
1808
|
+
let state = NORMAL;
|
|
1809
|
+
let wordStart = true;
|
|
1810
|
+
let domainStart = false;
|
|
1811
|
+
let depth = 0;
|
|
1812
|
+
let at = -1;
|
|
1813
|
+
const end = email.length;
|
|
1814
|
+
for (let i = 0; i < end; i++) {
|
|
1815
|
+
const code = codeAt(email, i);
|
|
1816
|
+
if (state === NORMAL) {
|
|
1817
|
+
if (code === 64) {
|
|
1818
|
+
at = i;
|
|
1819
|
+
wordStart = true;
|
|
1820
|
+
domainStart = true;
|
|
1821
|
+
} else if (code === 40 && rules.comments) {
|
|
1822
|
+
state = COMMENT;
|
|
1823
|
+
depth = 1;
|
|
1824
|
+
} else if (!isWhitespace(code)) {
|
|
1825
|
+
if (code === 34 && rules.quotes && wordStart) state = QUOTED;
|
|
1826
|
+
else if (code === 91 && rules.literals && domainStart) state = LITERAL;
|
|
1827
|
+
wordStart = code === 46;
|
|
1828
|
+
domainStart = false;
|
|
1829
|
+
}
|
|
1830
|
+
} else if (code === 92) i++;
|
|
1831
|
+
else if (state === COMMENT) {
|
|
1832
|
+
if (code === 40) depth++;
|
|
1833
|
+
else if (code === 41 && --depth === 0) state = NORMAL;
|
|
1834
|
+
} else if (code === (state === QUOTED ? 34 : 93)) state = NORMAL;
|
|
1835
|
+
}
|
|
1836
|
+
return at;
|
|
1837
|
+
}
|
|
1838
|
+
/**
|
|
1839
|
+
* Parses `email` under `rules`.
|
|
1840
|
+
*
|
|
1841
|
+
* @throws TypeError when `email` isn't a string.
|
|
1842
|
+
*/
|
|
1843
|
+
function parse(email, rules) {
|
|
1844
|
+
if (typeof email !== "string") throw new TypeError(`Expected a string, got ${typeof email}`);
|
|
1845
|
+
if (email === "") return fail("syntax.address.empty");
|
|
1846
|
+
if (email.length > rules.maxLength) return fail("syntax.address.too_long");
|
|
1847
|
+
const at = findAt(email, rules);
|
|
1848
|
+
if (at < 0) return fail("syntax.address.no_at");
|
|
1849
|
+
const comments = [];
|
|
1850
|
+
const local = scanLocal(email, at, rules, comments);
|
|
1851
|
+
if (typeof local !== "string") return local;
|
|
1852
|
+
const localSize = rules.unicode ? utf8Length(local) : local.length;
|
|
1853
|
+
if (localSize > rules.localCap) return fail("syntax.local.too_long");
|
|
1854
|
+
const domain = scanDomain(email, at, rules, comments);
|
|
1855
|
+
if ("reason" in domain) return domain;
|
|
1856
|
+
if (domain.size > rules.domainCap) return fail("syntax.domain.too_long");
|
|
1857
|
+
if (localSize + 1 + domain.size > 254) return fail("syntax.address.too_long");
|
|
1858
|
+
const { tld } = domain;
|
|
1859
|
+
if (tld === void 0 && !domain.literal && !rules.allowNoTld) return fail("syntax.domain.no_dot");
|
|
1860
|
+
if (tld !== void 0 && rules.checkTld && !isKnownTld(tld)) return fail("syntax.tld.unknown");
|
|
1861
|
+
return {
|
|
1862
|
+
ok: true,
|
|
1863
|
+
value: tld === void 0 ? {
|
|
1864
|
+
local,
|
|
1865
|
+
domain: domain.domain,
|
|
1866
|
+
comments
|
|
1867
|
+
} : {
|
|
1868
|
+
local,
|
|
1869
|
+
domain: domain.domain,
|
|
1870
|
+
tld,
|
|
1871
|
+
comments
|
|
1872
|
+
}
|
|
1873
|
+
};
|
|
1874
|
+
}
|
|
1875
|
+
/**
|
|
1876
|
+
* Scans the local part, `email` up to `at`, and returns it without comments
|
|
1877
|
+
* or folding whitespace.
|
|
1878
|
+
*/
|
|
1879
|
+
function scanLocal(email, at, rules, comments) {
|
|
1880
|
+
let local = "";
|
|
1881
|
+
let words = 0;
|
|
1882
|
+
let afterWord = false;
|
|
1883
|
+
let closed = false;
|
|
1884
|
+
let dot = -1;
|
|
1885
|
+
let space = -1;
|
|
1886
|
+
let edge = -1;
|
|
1887
|
+
let trailing = comments.length;
|
|
1888
|
+
let i = 0;
|
|
1889
|
+
while (i < at) {
|
|
1890
|
+
const code = codeAt(email, i);
|
|
1891
|
+
const quote = code === 34 && rules.quotes && (rules.obs || i === 0);
|
|
1892
|
+
const atom = inClass(code, rules.local);
|
|
1893
|
+
if (quote || atom || rules.unicode && nonAsciiAt(email, i, at) > 0) {
|
|
1894
|
+
if (edge >= 0) return fail("syntax.comment.not_allowed", edge);
|
|
1895
|
+
if (afterWord) return space >= 0 ? fail("syntax.local.unquoted_space", space) : fail("syntax.local.invalid_char", i);
|
|
1896
|
+
let next;
|
|
1897
|
+
if (quote) {
|
|
1898
|
+
next = skipQuoted(email, i, at, rules.obs, rules.unicode);
|
|
1899
|
+
if (next < 0) return fail("syntax.local.invalid_char", -1 - next);
|
|
1900
|
+
closed = !rules.obs;
|
|
1901
|
+
} else {
|
|
1902
|
+
next = atom ? i + 1 : i;
|
|
1903
|
+
while (next < at && inClass(codeAt(email, next), rules.local)) next++;
|
|
1904
|
+
if (rules.unicode) next = skipUnicode(email, next, at, rules.local);
|
|
1905
|
+
}
|
|
1906
|
+
local += unfold(email, i, next);
|
|
1907
|
+
words++;
|
|
1908
|
+
afterWord = true;
|
|
1909
|
+
dot = -1;
|
|
1910
|
+
space = -1;
|
|
1911
|
+
trailing = comments.length;
|
|
1912
|
+
i = next;
|
|
1913
|
+
} else if (code === 46) {
|
|
1914
|
+
if (edge >= 0) return fail("syntax.comment.not_allowed", edge);
|
|
1915
|
+
if (!afterWord || closed) return dot >= 0 ? fail("syntax.local.consecutive_dots", i) : fail("syntax.local.invalid_char", i);
|
|
1916
|
+
local += ".";
|
|
1917
|
+
afterWord = false;
|
|
1918
|
+
dot = i;
|
|
1919
|
+
space = -1;
|
|
1920
|
+
i++;
|
|
1921
|
+
} else if (code === 40 && rules.comments) {
|
|
1922
|
+
if (!rules.obs && words > 0) {
|
|
1923
|
+
if (!afterWord) return fail("syntax.comment.not_allowed", i);
|
|
1924
|
+
edge = edge < 0 ? i : edge;
|
|
1925
|
+
}
|
|
1926
|
+
const next = skipComment(email, i, at, rules.unicode);
|
|
1927
|
+
if (next < 0) return fail("syntax.local.invalid_char", -1 - next);
|
|
1928
|
+
comments.push({
|
|
1929
|
+
text: email.slice(i + 1, next - 1),
|
|
1930
|
+
position: words === 0 ? "before-local" : "inside-local"
|
|
1931
|
+
});
|
|
1932
|
+
i = next;
|
|
1933
|
+
} else if (code === 40) return fail("syntax.comment.not_allowed", i);
|
|
1934
|
+
else if (rules.obs && isWhitespace(code)) {
|
|
1935
|
+
const next = skipSpace(email, i, at);
|
|
1936
|
+
if (next < 0) return fail("syntax.local.invalid_char", i);
|
|
1937
|
+
space = space < 0 ? i : space;
|
|
1938
|
+
i = next;
|
|
1939
|
+
} else return code === 32 ? fail("syntax.local.unquoted_space", i) : fail("syntax.local.invalid_char", i);
|
|
1940
|
+
}
|
|
1941
|
+
if (words === 0) return fail("syntax.local.empty");
|
|
1942
|
+
if (dot >= 0) return fail("syntax.local.invalid_char", dot);
|
|
1943
|
+
settle(comments, trailing, "after-local");
|
|
1944
|
+
return local;
|
|
1945
|
+
}
|
|
1946
|
+
/**
|
|
1947
|
+
* Scans the domain, `email` after `at`, and returns it without comments or
|
|
1948
|
+
* folding whitespace.
|
|
1949
|
+
*/
|
|
1950
|
+
function scanDomain(email, at, rules, comments) {
|
|
1951
|
+
const uLabels = [];
|
|
1952
|
+
const domain = scanLabels(email, at, rules, comments, uLabels);
|
|
1953
|
+
if (uLabels.length === 0) return domain;
|
|
1954
|
+
const growth = checkULabels(email, uLabels, rules.domainCap);
|
|
1955
|
+
if (typeof growth !== "number") return growth;
|
|
1956
|
+
if (!("reason" in domain)) domain.size += growth;
|
|
1957
|
+
return domain;
|
|
1958
|
+
}
|
|
1959
|
+
/**
|
|
1960
|
+
* Checks the U-labels at `spans`, triples of start, end, and the length of
|
|
1961
|
+
* the domain before it, as A-labels: each must convert, and pass the
|
|
1962
|
+
* hostname rules as its A-label. Returns the first failure, or what the
|
|
1963
|
+
* A-labels add to the domain's length: `Infinity` once it's past `cap`.
|
|
1964
|
+
*
|
|
1965
|
+
* @remarks
|
|
1966
|
+
* The U-labels are converted a few at a time, about 32 characters of them
|
|
1967
|
+
* in each URL: one URL costs about as much as one label alone, and a small
|
|
1968
|
+
* batch wastes little past the first failure or past `cap`. Once the
|
|
1969
|
+
* A-labels take the domain past `cap`, the rest aren't checked: the domain
|
|
1970
|
+
* fails as too long, unless the scan found something earlier. Punycode's
|
|
1971
|
+
* cost grows with the square of a label's length, so converting labels that
|
|
1972
|
+
* can't change the outcome would cost the most on input built to be slow
|
|
1973
|
+
* (validator-syntax#15).
|
|
1974
|
+
*/
|
|
1975
|
+
function checkULabels(email, spans, cap) {
|
|
1976
|
+
let growth = 0;
|
|
1977
|
+
for (let first = 0; first < spans.length;) {
|
|
1978
|
+
const chunk = [];
|
|
1979
|
+
let written = 0;
|
|
1980
|
+
let next = first;
|
|
1981
|
+
while (next < spans.length && written < 32) {
|
|
1982
|
+
const label = email.slice(spans[next], spans[next + 1]);
|
|
1983
|
+
chunk.push(label);
|
|
1984
|
+
written += label.length;
|
|
1985
|
+
next += 3;
|
|
1986
|
+
}
|
|
1987
|
+
const aLabels = toALabels(chunk);
|
|
1988
|
+
for (let k = 0; k < chunk.length; k++) {
|
|
1989
|
+
const start = spans[first + 3 * k];
|
|
1990
|
+
const end = spans[first + 3 * k + 1];
|
|
1991
|
+
const aLabel = aLabels[k];
|
|
1992
|
+
if (aLabel === void 0) return fail("syntax.domain.label_invalid", start);
|
|
1993
|
+
const bad = checkLabel(email, start, end, aLabel.length);
|
|
1994
|
+
if (bad >= 0) return fail("syntax.domain.label_invalid", bad);
|
|
1995
|
+
growth += aLabel.length - (end - start);
|
|
1996
|
+
if (spans[first + 3 * k + 2] + (end - start) + growth > cap) return Infinity;
|
|
1997
|
+
}
|
|
1998
|
+
first = next;
|
|
1999
|
+
}
|
|
2000
|
+
return growth;
|
|
2001
|
+
}
|
|
2002
|
+
/**
|
|
2003
|
+
* The scan behind {@link scanDomain}, which leaves the U-labels it finds in
|
|
2004
|
+
* `uLabels`, as triples of start, end, and the domain's length before it,
|
|
2005
|
+
* unchecked but for their length.
|
|
2006
|
+
*/
|
|
2007
|
+
function scanLabels(email, at, rules, comments, uLabels) {
|
|
2008
|
+
const end = email.length;
|
|
2009
|
+
let domain = "";
|
|
2010
|
+
let labels = 0;
|
|
2011
|
+
let afterLabel = false;
|
|
2012
|
+
let literal = false;
|
|
2013
|
+
let dot = -1;
|
|
2014
|
+
let space = -1;
|
|
2015
|
+
let edge = -1;
|
|
2016
|
+
let trailing = comments.length;
|
|
2017
|
+
let tld = "";
|
|
2018
|
+
let i = at + 1;
|
|
2019
|
+
while (i < end) {
|
|
2020
|
+
const code = codeAt(email, i);
|
|
2021
|
+
const opensLiteral = code === 91 && rules.literals && labels === 0;
|
|
2022
|
+
const ldh = inClass(code, rules.domain);
|
|
2023
|
+
if (opensLiteral || ldh || rules.idn && nonAsciiAt(email, i, end) > 0) {
|
|
2024
|
+
if (edge >= 0) return fail("syntax.comment.not_allowed", edge);
|
|
2025
|
+
if (afterLabel) return fail("syntax.domain.invalid_char", space >= 0 ? space : i);
|
|
2026
|
+
let next;
|
|
2027
|
+
if (opensLiteral) {
|
|
2028
|
+
next = rules.obs ? skipLiteral(email, i, end) : skipAddressLiteral(email, i, end);
|
|
2029
|
+
if (next < 0) return fail("syntax.domain.literal_invalid", i);
|
|
2030
|
+
literal = true;
|
|
2031
|
+
} else {
|
|
2032
|
+
next = ldh ? i + 1 : i;
|
|
2033
|
+
while (next < end && inClass(codeAt(email, next), rules.domain)) next++;
|
|
2034
|
+
const ascii = next;
|
|
2035
|
+
if (rules.idn) next = skipUnicode(email, next, end, rules.domain);
|
|
2036
|
+
if (next > ascii) {
|
|
2037
|
+
if (codePoints(email, i, next) > 63) return fail("syntax.domain.label_invalid", i);
|
|
2038
|
+
uLabels.push(i, next, domain.length);
|
|
2039
|
+
} else {
|
|
2040
|
+
const bad = checkLabel(email, i, next, next - i);
|
|
2041
|
+
if (bad >= 0) return fail("syntax.domain.label_invalid", bad);
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
tld = unfold(email, i, next);
|
|
2045
|
+
domain += tld;
|
|
2046
|
+
labels++;
|
|
2047
|
+
afterLabel = true;
|
|
2048
|
+
dot = -1;
|
|
2049
|
+
space = -1;
|
|
2050
|
+
trailing = comments.length;
|
|
2051
|
+
i = next;
|
|
2052
|
+
} else if (code === 46) {
|
|
2053
|
+
if (edge >= 0) return fail("syntax.comment.not_allowed", edge);
|
|
2054
|
+
if (!afterLabel || literal) return literal ? fail("syntax.domain.invalid_char", i) : fail("syntax.domain.label_invalid", i);
|
|
2055
|
+
domain += ".";
|
|
2056
|
+
afterLabel = false;
|
|
2057
|
+
dot = i;
|
|
2058
|
+
space = -1;
|
|
2059
|
+
i++;
|
|
2060
|
+
} else if (code === 40 && rules.comments) {
|
|
2061
|
+
if (!rules.obs && labels > 0) {
|
|
2062
|
+
if (!afterLabel) return fail("syntax.comment.not_allowed", i);
|
|
2063
|
+
edge = edge < 0 ? i : edge;
|
|
2064
|
+
}
|
|
2065
|
+
const next = skipComment(email, i, end, rules.unicode);
|
|
2066
|
+
if (next < 0) return -1 - next === i ? fail("syntax.comment.unterminated", i) : fail("syntax.domain.invalid_char", -1 - next);
|
|
2067
|
+
comments.push({
|
|
2068
|
+
text: email.slice(i + 1, next - 1),
|
|
2069
|
+
position: labels === 0 ? "before-domain" : "inside-domain"
|
|
2070
|
+
});
|
|
2071
|
+
i = next;
|
|
2072
|
+
} else if (code === 40) return fail("syntax.comment.not_allowed", i);
|
|
2073
|
+
else if (rules.obs && isWhitespace(code)) {
|
|
2074
|
+
const next = skipSpace(email, i, end);
|
|
2075
|
+
if (next < 0) return fail("syntax.domain.invalid_char", i);
|
|
2076
|
+
space = space < 0 ? i : space;
|
|
2077
|
+
i = next;
|
|
2078
|
+
} else return fail("syntax.domain.invalid_char", i);
|
|
2079
|
+
}
|
|
2080
|
+
if (labels === 0) return fail("syntax.domain.empty");
|
|
2081
|
+
if (dot >= 0) return fail("syntax.domain.label_invalid", dot);
|
|
2082
|
+
settle(comments, trailing, "after-domain");
|
|
2083
|
+
const size = domain.length;
|
|
2084
|
+
return literal || labels === 1 ? {
|
|
2085
|
+
domain,
|
|
2086
|
+
literal,
|
|
2087
|
+
size
|
|
2088
|
+
} : {
|
|
2089
|
+
domain,
|
|
2090
|
+
tld,
|
|
2091
|
+
literal,
|
|
2092
|
+
size
|
|
2093
|
+
};
|
|
2094
|
+
}
|
|
2095
|
+
/**
|
|
2096
|
+
* Carries an atom or label on from `i`, where its ASCII run stopped, through
|
|
2097
|
+
* any non-ASCII characters and the class-`flag` characters after them.
|
|
2098
|
+
*/
|
|
2099
|
+
function skipUnicode(email, i, end, flag) {
|
|
2100
|
+
let width = i < end ? nonAsciiAt(email, i, end) : 0;
|
|
2101
|
+
while (width > 0) {
|
|
2102
|
+
i += width;
|
|
2103
|
+
while (i < end && inClass(codeAt(email, i), flag)) i++;
|
|
2104
|
+
width = i < end ? nonAsciiAt(email, i, end) : 0;
|
|
2105
|
+
}
|
|
2106
|
+
return i;
|
|
2107
|
+
}
|
|
2108
|
+
/**
|
|
2109
|
+
* Checks the hostname label from `start` to `end`, `size` characters long as
|
|
2110
|
+
* an A-label: returns the index of a leading or trailing hyphen, the start of
|
|
2111
|
+
* a label over 63 characters, or -1.
|
|
2112
|
+
*/
|
|
2113
|
+
function checkLabel(email, start, end, size) {
|
|
2114
|
+
if (codeAt(email, start) === 45) return start;
|
|
2115
|
+
if (size > 63) return start;
|
|
2116
|
+
return codeAt(email, end - 1) === 45 ? end - 1 : -1;
|
|
2117
|
+
}
|
|
2118
|
+
/** Marks the comments from `from` on, which no word follows, as trailing. */
|
|
2119
|
+
function settle(comments, from, position) {
|
|
2120
|
+
for (let c = from; c < comments.length; c++) {
|
|
2121
|
+
const comment = comments[c];
|
|
2122
|
+
if (comment.position.startsWith("inside")) comment.position = position;
|
|
2123
|
+
}
|
|
2124
|
+
}
|
|
2125
|
+
const { indexOf, slice } = String.prototype;
|
|
2126
|
+
/**
|
|
2127
|
+
* `email` from `start` to `end`, without the CRLFs of folding whitespace,
|
|
2128
|
+
* keeping the space or tab after each.
|
|
2129
|
+
*/
|
|
2130
|
+
function unfold(email, start, end) {
|
|
2131
|
+
const text = slice.call(email, start, end);
|
|
2132
|
+
return indexOf.call(text, "\r") < 0 ? text : text.replaceAll("\r\n", "");
|
|
2133
|
+
}
|
|
2134
|
+
/**
|
|
2135
|
+
* Skips one character of folding whitespace: a space, a tab, or a CRLF with
|
|
2136
|
+
* a space or tab after it. A lone CR or LF breaks it.
|
|
2137
|
+
*/
|
|
2138
|
+
function skipSpace(email, i, end) {
|
|
2139
|
+
const code = codeAt(email, i);
|
|
2140
|
+
if (code === 32 || code === 9) return i + 1;
|
|
2141
|
+
return code === 13 && i + 2 < end && codeAt(email, i + 1) === 10 && (codeAt(email, i + 2) === 32 || codeAt(email, i + 2) === 9) ? i + 2 : -1 - i;
|
|
2142
|
+
}
|
|
2143
|
+
/** Whether a backslash may escape `code`: any ASCII with `obs`, else VCHAR and space. */
|
|
2144
|
+
function escapable(code, obs) {
|
|
2145
|
+
return obs ? code < 128 : code >= 32 && code <= 126;
|
|
2146
|
+
}
|
|
2147
|
+
/**
|
|
2148
|
+
* Skips the quoted string opening at `open`. `obs` allows folding whitespace
|
|
2149
|
+
* and control characters other than NUL; without it, the string follows
|
|
2150
|
+
* RFC 5321: printable ASCII and spaces only. `unicode` adds non-ASCII.
|
|
2151
|
+
*/
|
|
2152
|
+
function skipQuoted(email, open, end, obs, unicode) {
|
|
2153
|
+
let i = open + 1;
|
|
2154
|
+
while (i < end) {
|
|
2155
|
+
const code = codeAt(email, i);
|
|
2156
|
+
if (code === 34) return i + 1;
|
|
2157
|
+
if (code === 92) {
|
|
2158
|
+
if (!escapable(codeAt(email, i + 1), obs)) return -2 - i;
|
|
2159
|
+
i += 2;
|
|
2160
|
+
} else if (obs && isWhitespace(code)) {
|
|
2161
|
+
i = skipSpace(email, i, end);
|
|
2162
|
+
if (i < 0) return i;
|
|
2163
|
+
} else if (obs ? code === 0 || code > 127 : code < 32 || code > 126) {
|
|
2164
|
+
const width = unicode ? nonAsciiAt(email, i, end) : 0;
|
|
2165
|
+
if (width === 0) return -1 - i;
|
|
2166
|
+
i += width;
|
|
2167
|
+
} else i++;
|
|
2168
|
+
}
|
|
2169
|
+
return -1 - open;
|
|
2170
|
+
}
|
|
2171
|
+
/**
|
|
2172
|
+
* Skips the comment opening at `open`, nested comments included. Its text
|
|
2173
|
+
* may hold any ASCII but NUL, with folding whitespace, and non-ASCII with
|
|
2174
|
+
* `unicode`; returns `-1 - open` when it never closes.
|
|
2175
|
+
*/
|
|
2176
|
+
function skipComment(email, open, end, unicode) {
|
|
2177
|
+
let depth = 1;
|
|
2178
|
+
let i = open + 1;
|
|
2179
|
+
while (i < end) {
|
|
2180
|
+
const code = codeAt(email, i);
|
|
2181
|
+
if (code === 40 || code === 41) {
|
|
2182
|
+
depth += code === 40 ? 1 : -1;
|
|
2183
|
+
i++;
|
|
2184
|
+
if (depth === 0) return i;
|
|
2185
|
+
} else if (code === 92) {
|
|
2186
|
+
if (i + 1 >= end) break;
|
|
2187
|
+
if (!escapable(codeAt(email, i + 1), true)) return -2 - i;
|
|
2188
|
+
i += 2;
|
|
2189
|
+
} else if (isWhitespace(code)) {
|
|
2190
|
+
i = skipSpace(email, i, end);
|
|
2191
|
+
if (i < 0) return i;
|
|
2192
|
+
} else if (code === 0 || code > 127) {
|
|
2193
|
+
const width = unicode ? nonAsciiAt(email, i, end) : 0;
|
|
2194
|
+
if (width === 0) return -1 - i;
|
|
2195
|
+
i += width;
|
|
2196
|
+
} else i++;
|
|
2197
|
+
}
|
|
2198
|
+
return -1 - open;
|
|
2199
|
+
}
|
|
2200
|
+
/**
|
|
2201
|
+
* Skips the RFC 5322 domain literal opening at `open`: any ASCII but NUL,
|
|
2202
|
+
* `[`, and `]`, with escapes and folding whitespace. Returns -1 when it's
|
|
2203
|
+
* malformed or never closes.
|
|
2204
|
+
*/
|
|
2205
|
+
function skipLiteral(email, open, end) {
|
|
2206
|
+
let i = open + 1;
|
|
2207
|
+
while (i < end) {
|
|
2208
|
+
const code = codeAt(email, i);
|
|
2209
|
+
if (code === 93) return i + 1;
|
|
2210
|
+
if (code === 92) {
|
|
2211
|
+
if (i + 1 >= end || !escapable(codeAt(email, i + 1), true)) return -1;
|
|
2212
|
+
i += 2;
|
|
2213
|
+
} else if (isWhitespace(code)) {
|
|
2214
|
+
i = skipSpace(email, i, end);
|
|
2215
|
+
if (i < 0) return -1;
|
|
2216
|
+
} else if (code === 0 || code === 91 || code > 127) return -1;
|
|
2217
|
+
else i++;
|
|
2218
|
+
}
|
|
2219
|
+
return -1;
|
|
2220
|
+
}
|
|
2221
|
+
/**
|
|
2222
|
+
* Skips the RFC 5321 address literal opening at `open`: an IPv4 address or
|
|
2223
|
+
* `IPv6:` and an IPv6 address. Returns -1 for anything else.
|
|
2224
|
+
*/
|
|
2225
|
+
function skipAddressLiteral(email, open, end) {
|
|
2226
|
+
const close = email.indexOf("]", open + 1);
|
|
2227
|
+
return close >= 0 && close < end && isAddressLiteral(email.slice(open + 1, close)) ? close + 1 : -1;
|
|
2228
|
+
}
|
|
2229
|
+
//#endregion
|
|
2230
|
+
//#region src/index.ts
|
|
2231
|
+
/**
|
|
2232
|
+
* Is the address well-formed? A quote-aware parser with four presets:
|
|
2233
|
+
* `practical` (the default), `rfc5321`, `rfc5322`, and `html5`.
|
|
2234
|
+
*
|
|
2235
|
+
* @packageDocumentation
|
|
2236
|
+
*/
|
|
2237
|
+
/**
|
|
2238
|
+
* Parses `email` into its local part, domain, TLD, and comments, or returns
|
|
2239
|
+
* the first check it fails.
|
|
2240
|
+
*
|
|
2241
|
+
* @remarks
|
|
2242
|
+
* Input longer than `maxLength` (512 UTF-16 code units by default) fails as
|
|
2243
|
+
* `syntax.address.too_long` before it's scanned. Otherwise the local part is
|
|
2244
|
+
* checked before the domain, each left to right, then the lengths, then a
|
|
2245
|
+
* dotless domain, then the TLD. `index`, where a failure has one, points at
|
|
2246
|
+
* the offending character.
|
|
2247
|
+
*
|
|
2248
|
+
* @example
|
|
2249
|
+
* ```ts
|
|
2250
|
+
* import { parseAddress } from '@email-utils/validator-syntax';
|
|
2251
|
+
*
|
|
2252
|
+
* parseAddress('ada.lovelace@example.co.uk');
|
|
2253
|
+
* // => { ok: true, value: { local: 'ada.lovelace', tld: 'uk' } }
|
|
2254
|
+
* parseAddress('ada..lovelace@example.com');
|
|
2255
|
+
* // => { ok: false, reason: 'syntax.local.consecutive_dots', index: 4 }
|
|
2256
|
+
* ```
|
|
2257
|
+
*
|
|
2258
|
+
* @throws TypeError when `email` isn't a string, or `options` are malformed.
|
|
2259
|
+
*/
|
|
2260
|
+
function parseAddress(email, options) {
|
|
2261
|
+
return parse(email, resolve(options));
|
|
2262
|
+
}
|
|
2263
|
+
/**
|
|
2264
|
+
* Whether `email` is well-formed: exactly `parseAddress(email, options).ok`.
|
|
2265
|
+
*
|
|
2266
|
+
* @example
|
|
2267
|
+
* ```ts
|
|
2268
|
+
* import { isValidSyntax } from '@email-utils/validator-syntax';
|
|
2269
|
+
*
|
|
2270
|
+
* isValidSyntax('ada@example.com'); // => true
|
|
2271
|
+
* isValidSyntax('"ada"@example.com'); // => false
|
|
2272
|
+
* isValidSyntax('"ada"@example.com', { preset: 'rfc5321' }); // => true
|
|
2273
|
+
* ```
|
|
2274
|
+
*
|
|
2275
|
+
* @throws TypeError when `email` isn't a string, or `options` are malformed.
|
|
2276
|
+
*/
|
|
2277
|
+
function isValidSyntax(email, options) {
|
|
2278
|
+
return parse(email, resolve(options)).ok;
|
|
2279
|
+
}
|
|
2280
|
+
/**
|
|
2281
|
+
* Binds `options` once, checking them up front, and returns
|
|
2282
|
+
* {@link parseAddress} and {@link isValidSyntax} with them applied.
|
|
2283
|
+
*
|
|
2284
|
+
* @example
|
|
2285
|
+
* ```ts
|
|
2286
|
+
* import { createSyntaxValidator } from '@email-utils/validator-syntax';
|
|
2287
|
+
*
|
|
2288
|
+
* const strict = createSyntaxValidator({ preset: 'rfc5321' });
|
|
2289
|
+
* strict.parse('a b@example.com');
|
|
2290
|
+
* // => { ok: false, reason: 'syntax.local.unquoted_space', index: 1 }
|
|
2291
|
+
* strict.isValid('"a b"@example.com'); // => true
|
|
2292
|
+
* createSyntaxValidator({ preset: 'html5', allowComments: true });
|
|
2293
|
+
* // => throws TypeError
|
|
2294
|
+
* ```
|
|
2295
|
+
*
|
|
2296
|
+
* @throws TypeError when `options` are malformed.
|
|
2297
|
+
*/
|
|
2298
|
+
function createSyntaxValidator(options) {
|
|
2299
|
+
const rules = resolve(options);
|
|
2300
|
+
return {
|
|
2301
|
+
parse: (email) => parse(email, rules),
|
|
2302
|
+
isValid: (email) => parse(email, rules).ok
|
|
2303
|
+
};
|
|
2304
|
+
}
|
|
2305
|
+
//#endregion
|
|
2306
|
+
exports.createSyntaxValidator = createSyntaxValidator;
|
|
2307
|
+
exports.isValidSyntax = isValidSyntax;
|
|
2308
|
+
exports.parseAddress = parseAddress;
|
|
2309
|
+
|
|
2310
|
+
//# sourceMappingURL=index.cjs.map
|