From 5445d6309eb23d46dfe7b53433ec9efce8979ac5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carl-Gerhard=20Lindesv=C3=A4rd?= <1987198+lindesvard@users.noreply.github.com> Date: Fri, 6 Jun 2025 19:14:18 +0200 Subject: [PATCH] test: add vitest * feature(root): add vitest and some basic tests * fix(test): after rebase + added referrars test and more sites * fix(test): test broken after rebase * fix(test): provide db url to make prisma happy * fix tests --- apps/api/package.json | 1 - apps/api/scripts/get-referrers.ts | 56 - apps/api/src/referrers/index.ts | 2685 ----------------- apps/api/src/referrers/referrers.readme.md | 5 - apps/worker/package.json | 4 +- apps/worker/scripts/get-referrers.ts | 91 + apps/worker/src/jobs/events.incoming-event.ts | 30 +- .../src/jobs/events.incoming-events.test.ts | 675 +++-- apps/worker/src/referrers/index.ts | 37 +- apps/worker/src/utils/parse-referrer.test.ts | 117 + apps/worker/src/utils/session-handler.ts | 2 +- apps/worker/vitest.config.ts | 3 + package.json | 6 +- packages/common/package.json | 1 + .../common/server/parser-user-agent.test.ts | 170 ++ packages/common/server/parser-user-agent.ts | 23 +- packages/common/vitest.config.ts | 3 + packages/logger/index.ts | 2 +- packages/queue/index.ts | 1 - packages/queue/src/utils.ts | 40 - pnpm-lock.yaml | 284 +- vitest.shared.ts | 27 + vitest.workspace.ts | 1 + 23 files changed, 1131 insertions(+), 3133 deletions(-) delete mode 100644 apps/api/scripts/get-referrers.ts delete mode 100644 apps/api/src/referrers/index.ts delete mode 100644 apps/api/src/referrers/referrers.readme.md create mode 100644 apps/worker/scripts/get-referrers.ts create mode 100644 apps/worker/src/utils/parse-referrer.test.ts create mode 100644 apps/worker/vitest.config.ts create mode 100644 packages/common/server/parser-user-agent.test.ts create mode 100644 packages/common/vitest.config.ts delete mode 100644 packages/queue/src/utils.ts create mode 100644 vitest.shared.ts create mode 100644 vitest.workspace.ts diff --git a/apps/api/package.json b/apps/api/package.json index 54641517..d1b431ba 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -6,7 +6,6 @@ "testing": "API_PORT=3333 pnpm dev", "start": "node dist/index.js", "build": "rm -rf dist && tsup", - "gen:referrers": "jiti scripts/get-referrers.ts && biome format --write src/referrers/index.ts", "gen:bots": "jiti scripts/get-bots.ts && biome format --write src/bots/bots.ts", "typecheck": "tsc --noEmit" }, diff --git a/apps/api/scripts/get-referrers.ts b/apps/api/scripts/get-referrers.ts deleted file mode 100644 index b2c5f3d1..00000000 --- a/apps/api/scripts/get-referrers.ts +++ /dev/null @@ -1,56 +0,0 @@ -import fs from 'node:fs'; -import path from 'node:path'; - -// extras -const extraReferrers = { - 'bsky.app': { type: 'social', name: 'Bluesky' }, -}; - -function transform(data: any) { - const obj: Record = {}; - for (const type in data) { - for (const name in data[type]) { - const domains = data[type][name].domains ?? []; - for (const domain of domains) { - obj[domain] = { - type, - name, - }; - } - } - } - - return obj; -} - -async function main() { - // Get document, or throw exception on error - try { - const data = await fetch( - 'https://s3-eu-west-1.amazonaws.com/snowplow-hosted-assets/third-party/referer-parser/referers-latest.json', - ).then((res) => res.json()); - - fs.writeFileSync( - path.resolve(__dirname, '../src/referrers/index.ts'), - [ - '// This file is generated by the script get-referrers.ts', - '', - '// The data is fetch from snowplow-referer-parser https://github.com/snowplow-referer-parser/referer-parser', - `// The orginal referers.yml is based on Piwik's SearchEngines.php and Socials.php, copyright 2012 Matthieu Aubry and available under the GNU General Public License v3.`, - '', - `const referrers: Record = ${JSON.stringify( - { - ...transform(data), - ...extraReferrers, - }, - )} as const;`, - 'export default referrers;', - ].join('\n'), - 'utf-8', - ); - } catch (e) { - console.log(e); - } -} - -main(); diff --git a/apps/api/src/referrers/index.ts b/apps/api/src/referrers/index.ts deleted file mode 100644 index ab704264..00000000 --- a/apps/api/src/referrers/index.ts +++ /dev/null @@ -1,2685 +0,0 @@ -// This file is generated by the script get-referrers.ts - -// The data is fetch from snowplow-referer-parser https://github.com/snowplow-referer-parser/referer-parser -// The orginal referers.yml is based on Piwik's SearchEngines.php and Socials.php, copyright 2012 Matthieu Aubry and available under the GNU General Public License v3. - -const referrers: Record = { - 'support.google.com': { type: 'unknown', name: 'Google' }, - 'developers.google.com': { type: 'unknown', name: 'Google' }, - 'maps.google.com': { type: 'unknown', name: 'Google' }, - 'accounts.google.com': { type: 'unknown', name: 'Google' }, - 'drive.google.com': { type: 'unknown', name: 'Google' }, - 'sites.google.com': { type: 'unknown', name: 'Google' }, - 'groups.google.com': { type: 'unknown', name: 'Google' }, - 'groups.google.co.uk': { type: 'unknown', name: 'Google' }, - 'maps.yandex.ru': { type: 'unknown', name: 'Yandex Maps' }, - 'maps.yandex.ua': { type: 'unknown', name: 'Yandex Maps' }, - 'maps.yandex.com': { type: 'unknown', name: 'Yandex Maps' }, - 'maps.yandex.by': { type: 'unknown', name: 'Yandex Maps' }, - 'n.maps.yandex.ru': { type: 'unknown', name: 'Yandex Maps' }, - 'finance.yahoo.com': { type: 'unknown', name: 'Yahoo!' }, - 'news.yahoo.com': { type: 'unknown', name: 'Yahoo!' }, - 'eurosport.yahoo.com': { type: 'unknown', name: 'Yahoo!' }, - 'sports.yahoo.com': { type: 'unknown', name: 'Yahoo!' }, - 'astrology.yahoo.com': { type: 'unknown', name: 'Yahoo!' }, - 'travel.yahoo.com': { type: 'unknown', name: 'Yahoo!' }, - 'answers.yahoo.com': { type: 'unknown', name: 'Yahoo!' }, - 'screen.yahoo.com': { type: 'unknown', name: 'Yahoo!' }, - 'weather.yahoo.com': { type: 'unknown', name: 'Yahoo!' }, - 'messenger.yahoo.com': { type: 'unknown', name: 'Yahoo!' }, - 'games.yahoo.com': { type: 'unknown', name: 'Yahoo!' }, - 'shopping.yahoo.net': { type: 'unknown', name: 'Yahoo!' }, - 'movies.yahoo.com': { type: 'unknown', name: 'Yahoo!' }, - 'cars.yahoo.com': { type: 'unknown', name: 'Yahoo!' }, - 'lifestyle.yahoo.com': { type: 'unknown', name: 'Yahoo!' }, - 'omg.yahoo.com': { type: 'unknown', name: 'Yahoo!' }, - 'match.yahoo.net': { type: 'unknown', name: 'Yahoo!' }, - 'www.talktalk.co.uk': { type: 'search', name: 'TalkTalk' }, - '1.cz': { type: 'search', name: '1.cz' }, - 'search.softonic.com': { type: 'search', name: 'Softonic' }, - 'gais.cs.ccu.edu.tw': { type: 'search', name: 'GAIS' }, - 'search.freecause.com': { type: 'search', name: 'Freecause' }, - 'so.360.cn': { type: 'search', name: '360.cn' }, - 'www.so.com': { type: 'search', name: '360.cn' }, - 'rpmfind.net': { type: 'search', name: 'RPMFind' }, - 'fr2.rpmfind.net': { type: 'search', name: 'RPMFind' }, - 'serach.comcast.net': { type: 'search', name: 'Comcast' }, - 'search.ke.voila.fr': { type: 'search', name: 'Voila' }, - 'www.lemoteur.fr': { type: 'search', name: 'Voila' }, - 'search.nifty.com': { type: 'search', name: 'Nifty' }, - 'searchatlas.centrum.cz': { type: 'search', name: 'Atlas' }, - '2gis.ru': { type: 'search', name: '2gis' }, - 'www.2gis.ru': { type: 'search', name: '2gis' }, - 'link.2gis.ru': { type: 'search', name: '2gis' }, - 'www.link.2gis.ru': { type: 'search', name: '2gis' }, - 'lo.st': { type: 'search', name: 'Lo.st' }, - 'www1.dastelefonbuch.de': { type: 'search', name: 'DasTelefonbuch' }, - 'www.fireball.de': { type: 'search', name: 'Fireball' }, - 'search.1und1.de': { type: 'search', name: '1und1' }, - 'ricerca.virgilio.it': { type: 'search', name: 'Virgilio' }, - 'ricercaimmagini.virgilio.it': { type: 'search', name: 'Virgilio' }, - 'ricercavideo.virgilio.it': { type: 'search', name: 'Virgilio' }, - 'ricercanews.virgilio.it': { type: 'search', name: 'Virgilio' }, - 'mobile.virgilio.it': { type: 'search', name: 'Virgilio' }, - 'search.media.telstra.com.au': { type: 'search', name: 'Telstra' }, - 'www.web.nl': { type: 'search', name: 'Web.nl' }, - 'www.plazoo.com': { type: 'search', name: 'Plazoo' }, - 'www.goyellow.de': { type: 'search', name: 'Goyellow.de' }, - 'search.aol.com': { type: 'search', name: 'AOL' }, - 'search.aol.it': { type: 'search', name: 'AOL' }, - 'aolsearch.aol.com': { type: 'search', name: 'AOL' }, - 'aolsearch.com': { type: 'search', name: 'AOL' }, - 'www.aolrecherche.aol.fr': { type: 'search', name: 'AOL' }, - 'www.aolrecherches.aol.fr': { type: 'search', name: 'AOL' }, - 'www.aolimages.aol.fr': { type: 'search', name: 'AOL' }, - 'aim.search.aol.com': { type: 'search', name: 'AOL' }, - 'www.recherche.aol.fr': { type: 'search', name: 'AOL' }, - 'recherche.aol.fr': { type: 'search', name: 'AOL' }, - 'find.web.aol.com': { type: 'search', name: 'AOL' }, - 'recherche.aol.ca': { type: 'search', name: 'AOL' }, - 'aolsearch.aol.co.uk': { type: 'search', name: 'AOL' }, - 'search.aol.co.uk': { type: 'search', name: 'AOL' }, - 'aolrecherche.aol.fr': { type: 'search', name: 'AOL' }, - 'sucheaol.aol.de': { type: 'search', name: 'AOL' }, - 'suche.aol.de': { type: 'search', name: 'AOL' }, - 'suche.aolsvc.de': { type: 'search', name: 'AOL' }, - 'aolbusqueda.aol.com.mx': { type: 'search', name: 'AOL' }, - 'alicesuche.aol.de': { type: 'search', name: 'AOL' }, - 'alicesuchet.aol.de': { type: 'search', name: 'AOL' }, - 'suchet2.aol.de': { type: 'search', name: 'AOL' }, - 'search.hp.my.aol.com.au': { type: 'search', name: 'AOL' }, - 'search.hp.my.aol.de': { type: 'search', name: 'AOL' }, - 'search.hp.my.aol.it': { type: 'search', name: 'AOL' }, - 'search-intl.netscape.com': { type: 'search', name: 'AOL' }, - 'www.acoon.de': { type: 'search', name: 'Acoon' }, - 'search.free.fr': { type: 'search', name: 'Free' }, - 'search1-2.free.fr': { type: 'search', name: 'Free' }, - 'search1-1.free.fr': { type: 'search', name: 'Free' }, - 'apollo.lv/portal/search/': { type: 'search', name: 'Apollo Latvia' }, - 'www.highbeam.com': { type: 'search', name: 'HighBeam' }, - 'start.iplay.com': { type: 'search', name: 'I-play' }, - 'friendfeed.com': { type: 'search', name: 'FriendFeed' }, - 'www.yasni.de': { type: 'search', name: 'Yasni' }, - 'www.yasni.com': { type: 'search', name: 'Yasni' }, - 'www.yasni.co.uk': { type: 'search', name: 'Yasni' }, - 'www.yasni.ch': { type: 'search', name: 'Yasni' }, - 'www.yasni.at': { type: 'search', name: 'Yasni' }, - 'www.gigablast.com': { type: 'search', name: 'Gigablast' }, - 'dir.gigablast.com': { type: 'search', name: 'Gigablast' }, - 'www.arcor.de': { type: 'search', name: 'Arcor' }, - 'arama.com': { type: 'search', name: 'arama' }, - 'www.fixsuche.de': { type: 'search', name: 'Fixsuche' }, - 'apontador.com.br': { type: 'search', name: 'Apontador' }, - 'www.apontador.com.br': { type: 'search', name: 'Apontador' }, - 'www.search.com': { type: 'search', name: 'Search.com' }, - 'www.monstercrawler.com': { type: 'search', name: 'Monstercrawler' }, - 'google.ac/imgres': { type: 'search', name: 'Google Images' }, - 'google.ad/imgres': { type: 'search', name: 'Google Images' }, - 'google.ae/imgres': { type: 'search', name: 'Google Images' }, - 'google.am/imgres': { type: 'search', name: 'Google Images' }, - 'google.as/imgres': { type: 'search', name: 'Google Images' }, - 'google.at/imgres': { type: 'search', name: 'Google Images' }, - 'google.az/imgres': { type: 'search', name: 'Google Images' }, - 'google.ba/imgres': { type: 'search', name: 'Google Images' }, - 'google.be/imgres': { type: 'search', name: 'Google Images' }, - 'google.bf/imgres': { type: 'search', name: 'Google Images' }, - 'google.bg/imgres': { type: 'search', name: 'Google Images' }, - 'google.bi/imgres': { type: 'search', name: 'Google Images' }, - 'google.bj/imgres': { type: 'search', name: 'Google Images' }, - 'google.bs/imgres': { type: 'search', name: 'Google Images' }, - 'google.by/imgres': { type: 'search', name: 'Google Images' }, - 'google.ca/imgres': { type: 'search', name: 'Google Images' }, - 'google.cat/imgres': { type: 'search', name: 'Google Images' }, - 'google.cc/imgres': { type: 'search', name: 'Google Images' }, - 'google.cd/imgres': { type: 'search', name: 'Google Images' }, - 'google.cf/imgres': { type: 'search', name: 'Google Images' }, - 'google.cg/imgres': { type: 'search', name: 'Google Images' }, - 'google.ch/imgres': { type: 'search', name: 'Google Images' }, - 'google.ci/imgres': { type: 'search', name: 'Google Images' }, - 'google.cl/imgres': { type: 'search', name: 'Google Images' }, - 'google.cm/imgres': { type: 'search', name: 'Google Images' }, - 'google.cn/imgres': { type: 'search', name: 'Google Images' }, - 'google.co.bw/imgres': { type: 'search', name: 'Google Images' }, - 'google.co.ck/imgres': { type: 'search', name: 'Google Images' }, - 'google.co.cr/imgres': { type: 'search', name: 'Google Images' }, - 'google.co.id/imgres': { type: 'search', name: 'Google Images' }, - 'google.co.il/imgres': { type: 'search', name: 'Google Images' }, - 'google.co.in/imgres': { type: 'search', name: 'Google Images' }, - 'google.co.jp/imgres': { type: 'search', name: 'Google Images' }, - 'google.co.ke/imgres': { type: 'search', name: 'Google Images' }, - 'google.co.kr/imgres': { type: 'search', name: 'Google Images' }, - 'google.co.ls/imgres': { type: 'search', name: 'Google Images' }, - 'google.co.ma/imgres': { type: 'search', name: 'Google Images' }, - 'google.co.mz/imgres': { type: 'search', name: 'Google Images' }, - 'google.co.nz/imgres': { type: 'search', name: 'Google Images' }, - 'google.co.th/imgres': { type: 'search', name: 'Google Images' }, - 'google.co.tz/imgres': { type: 'search', name: 'Google Images' }, - 'google.co.ug/imgres': { type: 'search', name: 'Google Images' }, - 'google.co.uk/imgres': { type: 'search', name: 'Google Images' }, - 'google.co.uz/imgres': { type: 'search', name: 'Google Images' }, - 'google.co.ve/imgres': { type: 'search', name: 'Google Images' }, - 'google.co.vi/imgres': { type: 'search', name: 'Google Images' }, - 'google.co.za/imgres': { type: 'search', name: 'Google Images' }, - 'google.co.zm/imgres': { type: 'search', name: 'Google Images' }, - 'google.co.zw/imgres': { type: 'search', name: 'Google Images' }, - 'google.com/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.af/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.ag/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.ai/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.ar/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.au/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.bd/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.bh/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.bn/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.bo/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.br/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.by/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.bz/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.co/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.cu/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.cy/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.do/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.ec/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.eg/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.et/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.fj/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.gh/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.gi/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.gt/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.hk/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.jm/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.kh/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.kw/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.lb/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.lc/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.ly/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.mt/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.mx/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.my/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.na/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.nf/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.ng/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.ni/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.np/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.om/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.pa/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.pe/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.ph/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.pk/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.pr/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.py/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.qa/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.sa/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.sb/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.sg/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.sl/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.sv/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.tj/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.tn/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.tr/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.tw/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.ua/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.uy/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.vc/imgres': { type: 'search', name: 'Google Images' }, - 'google.com.vn/imgres': { type: 'search', name: 'Google Images' }, - 'google.cv/imgres': { type: 'search', name: 'Google Images' }, - 'google.cz/imgres': { type: 'search', name: 'Google Images' }, - 'google.de/imgres': { type: 'search', name: 'Google Images' }, - 'google.dj/imgres': { type: 'search', name: 'Google Images' }, - 'google.dk/imgres': { type: 'search', name: 'Google Images' }, - 'google.dm/imgres': { type: 'search', name: 'Google Images' }, - 'google.dz/imgres': { type: 'search', name: 'Google Images' }, - 'google.ee/imgres': { type: 'search', name: 'Google Images' }, - 'google.es/imgres': { type: 'search', name: 'Google Images' }, - 'google.fi/imgres': { type: 'search', name: 'Google Images' }, - 'google.fm/imgres': { type: 'search', name: 'Google Images' }, - 'google.fr/imgres': { type: 'search', name: 'Google Images' }, - 'google.ga/imgres': { type: 'search', name: 'Google Images' }, - 'google.gd/imgres': { type: 'search', name: 'Google Images' }, - 'google.ge/imgres': { type: 'search', name: 'Google Images' }, - 'google.gf/imgres': { type: 'search', name: 'Google Images' }, - 'google.gg/imgres': { type: 'search', name: 'Google Images' }, - 'google.gl/imgres': { type: 'search', name: 'Google Images' }, - 'google.gm/imgres': { type: 'search', name: 'Google Images' }, - 'google.gp/imgres': { type: 'search', name: 'Google Images' }, - 'google.gr/imgres': { type: 'search', name: 'Google Images' }, - 'google.gy/imgres': { type: 'search', name: 'Google Images' }, - 'google.hn/imgres': { type: 'search', name: 'Google Images' }, - 'google.hr/imgres': { type: 'search', name: 'Google Images' }, - 'google.ht/imgres': { type: 'search', name: 'Google Images' }, - 'google.hu/imgres': { type: 'search', name: 'Google Images' }, - 'google.ie/imgres': { type: 'search', name: 'Google Images' }, - 'google.im/imgres': { type: 'search', name: 'Google Images' }, - 'google.io/imgres': { type: 'search', name: 'Google Images' }, - 'google.iq/imgres': { type: 'search', name: 'Google Images' }, - 'google.is/imgres': { type: 'search', name: 'Google Images' }, - 'google.it/imgres': { type: 'search', name: 'Google Images' }, - 'google.it.ao/imgres': { type: 'search', name: 'Google Images' }, - 'google.je/imgres': { type: 'search', name: 'Google Images' }, - 'google.jo/imgres': { type: 'search', name: 'Google Images' }, - 'google.kg/imgres': { type: 'search', name: 'Google Images' }, - 'google.ki/imgres': { type: 'search', name: 'Google Images' }, - 'google.kz/imgres': { type: 'search', name: 'Google Images' }, - 'google.la/imgres': { type: 'search', name: 'Google Images' }, - 'google.li/imgres': { type: 'search', name: 'Google Images' }, - 'google.lk/imgres': { type: 'search', name: 'Google Images' }, - 'google.lt/imgres': { type: 'search', name: 'Google Images' }, - 'google.lu/imgres': { type: 'search', name: 'Google Images' }, - 'google.lv/imgres': { type: 'search', name: 'Google Images' }, - 'google.md/imgres': { type: 'search', name: 'Google Images' }, - 'google.me/imgres': { type: 'search', name: 'Google Images' }, - 'google.mg/imgres': { type: 'search', name: 'Google Images' }, - 'google.mk/imgres': { type: 'search', name: 'Google Images' }, - 'google.ml/imgres': { type: 'search', name: 'Google Images' }, - 'google.mn/imgres': { type: 'search', name: 'Google Images' }, - 'google.ms/imgres': { type: 'search', name: 'Google Images' }, - 'google.mu/imgres': { type: 'search', name: 'Google Images' }, - 'google.mv/imgres': { type: 'search', name: 'Google Images' }, - 'google.mw/imgres': { type: 'search', name: 'Google Images' }, - 'google.ne/imgres': { type: 'search', name: 'Google Images' }, - 'google.nl/imgres': { type: 'search', name: 'Google Images' }, - 'google.no/imgres': { type: 'search', name: 'Google Images' }, - 'google.nr/imgres': { type: 'search', name: 'Google Images' }, - 'google.nu/imgres': { type: 'search', name: 'Google Images' }, - 'google.pl/imgres': { type: 'search', name: 'Google Images' }, - 'google.pn/imgres': { type: 'search', name: 'Google Images' }, - 'google.ps/imgres': { type: 'search', name: 'Google Images' }, - 'google.pt/imgres': { type: 'search', name: 'Google Images' }, - 'google.ro/imgres': { type: 'search', name: 'Google Images' }, - 'google.rs/imgres': { type: 'search', name: 'Google Images' }, - 'google.ru/imgres': { type: 'search', name: 'Google Images' }, - 'google.rw/imgres': { type: 'search', name: 'Google Images' }, - 'google.sc/imgres': { type: 'search', name: 'Google Images' }, - 'google.se/imgres': { type: 'search', name: 'Google Images' }, - 'google.sh/imgres': { type: 'search', name: 'Google Images' }, - 'google.si/imgres': { type: 'search', name: 'Google Images' }, - 'google.sk/imgres': { type: 'search', name: 'Google Images' }, - 'google.sm/imgres': { type: 'search', name: 'Google Images' }, - 'google.sn/imgres': { type: 'search', name: 'Google Images' }, - 'google.so/imgres': { type: 'search', name: 'Google Images' }, - 'google.st/imgres': { type: 'search', name: 'Google Images' }, - 'google.td/imgres': { type: 'search', name: 'Google Images' }, - 'google.tg/imgres': { type: 'search', name: 'Google Images' }, - 'google.tk/imgres': { type: 'search', name: 'Google Images' }, - 'google.tl/imgres': { type: 'search', name: 'Google Images' }, - 'google.tm/imgres': { type: 'search', name: 'Google Images' }, - 'google.to/imgres': { type: 'search', name: 'Google Images' }, - 'google.tt/imgres': { type: 'search', name: 'Google Images' }, - 'google.us/imgres': { type: 'search', name: 'Google Images' }, - 'google.vg/imgres': { type: 'search', name: 'Google Images' }, - 'google.vu/imgres': { type: 'search', name: 'Google Images' }, - 'images.google.ws': { type: 'search', name: 'Google Images' }, - 'images.google.ac': { type: 'search', name: 'Google Images' }, - 'images.google.ad': { type: 'search', name: 'Google Images' }, - 'images.google.ae': { type: 'search', name: 'Google Images' }, - 'images.google.am': { type: 'search', name: 'Google Images' }, - 'images.google.as': { type: 'search', name: 'Google Images' }, - 'images.google.at': { type: 'search', name: 'Google Images' }, - 'images.google.az': { type: 'search', name: 'Google Images' }, - 'images.google.ba': { type: 'search', name: 'Google Images' }, - 'images.google.be': { type: 'search', name: 'Google Images' }, - 'images.google.bf': { type: 'search', name: 'Google Images' }, - 'images.google.bg': { type: 'search', name: 'Google Images' }, - 'images.google.bi': { type: 'search', name: 'Google Images' }, - 'images.google.bj': { type: 'search', name: 'Google Images' }, - 'images.google.bs': { type: 'search', name: 'Google Images' }, - 'images.google.by': { type: 'search', name: 'Google Images' }, - 'images.google.ca': { type: 'search', name: 'Google Images' }, - 'images.google.cat': { type: 'search', name: 'Google Images' }, - 'images.google.cc': { type: 'search', name: 'Google Images' }, - 'images.google.cd': { type: 'search', name: 'Google Images' }, - 'images.google.cf': { type: 'search', name: 'Google Images' }, - 'images.google.cg': { type: 'search', name: 'Google Images' }, - 'images.google.ch': { type: 'search', name: 'Google Images' }, - 'images.google.ci': { type: 'search', name: 'Google Images' }, - 'images.google.cl': { type: 'search', name: 'Google Images' }, - 'images.google.cm': { type: 'search', name: 'Google Images' }, - 'images.google.cn': { type: 'search', name: 'Google Images' }, - 'images.google.co.bw': { type: 'search', name: 'Google Images' }, - 'images.google.co.ck': { type: 'search', name: 'Google Images' }, - 'images.google.co.cr': { type: 'search', name: 'Google Images' }, - 'images.google.co.id': { type: 'search', name: 'Google Images' }, - 'images.google.co.il': { type: 'search', name: 'Google Images' }, - 'images.google.co.in': { type: 'search', name: 'Google Images' }, - 'images.google.co.jp': { type: 'search', name: 'Google Images' }, - 'images.google.co.ke': { type: 'search', name: 'Google Images' }, - 'images.google.co.kr': { type: 'search', name: 'Google Images' }, - 'images.google.co.ls': { type: 'search', name: 'Google Images' }, - 'images.google.co.ma': { type: 'search', name: 'Google Images' }, - 'images.google.co.mz': { type: 'search', name: 'Google Images' }, - 'images.google.co.nz': { type: 'search', name: 'Google Images' }, - 'images.google.co.th': { type: 'search', name: 'Google Images' }, - 'images.google.co.tz': { type: 'search', name: 'Google Images' }, - 'images.google.co.ug': { type: 'search', name: 'Google Images' }, - 'images.google.co.uk': { type: 'search', name: 'Google Images' }, - 'images.google.co.uz': { type: 'search', name: 'Google Images' }, - 'images.google.co.ve': { type: 'search', name: 'Google Images' }, - 'images.google.co.vi': { type: 'search', name: 'Google Images' }, - 'images.google.co.za': { type: 'search', name: 'Google Images' }, - 'images.google.co.zm': { type: 'search', name: 'Google Images' }, - 'images.google.co.zw': { type: 'search', name: 'Google Images' }, - 'images.google.com': { type: 'search', name: 'Google Images' }, - 'images.google.com.af': { type: 'search', name: 'Google Images' }, - 'images.google.com.ag': { type: 'search', name: 'Google Images' }, - 'images.google.com.ai': { type: 'search', name: 'Google Images' }, - 'images.google.com.ar': { type: 'search', name: 'Google Images' }, - 'images.google.com.au': { type: 'search', name: 'Google Images' }, - 'images.google.com.bd': { type: 'search', name: 'Google Images' }, - 'images.google.com.bh': { type: 'search', name: 'Google Images' }, - 'images.google.com.bn': { type: 'search', name: 'Google Images' }, - 'images.google.com.bo': { type: 'search', name: 'Google Images' }, - 'images.google.com.br': { type: 'search', name: 'Google Images' }, - 'images.google.com.by': { type: 'search', name: 'Google Images' }, - 'images.google.com.bz': { type: 'search', name: 'Google Images' }, - 'images.google.com.co': { type: 'search', name: 'Google Images' }, - 'images.google.com.cu': { type: 'search', name: 'Google Images' }, - 'images.google.com.cy': { type: 'search', name: 'Google Images' }, - 'images.google.com.do': { type: 'search', name: 'Google Images' }, - 'images.google.com.ec': { type: 'search', name: 'Google Images' }, - 'images.google.com.eg': { type: 'search', name: 'Google Images' }, - 'images.google.com.et': { type: 'search', name: 'Google Images' }, - 'images.google.com.fj': { type: 'search', name: 'Google Images' }, - 'images.google.com.gh': { type: 'search', name: 'Google Images' }, - 'images.google.com.gi': { type: 'search', name: 'Google Images' }, - 'images.google.com.gt': { type: 'search', name: 'Google Images' }, - 'images.google.com.hk': { type: 'search', name: 'Google Images' }, - 'images.google.com.jm': { type: 'search', name: 'Google Images' }, - 'images.google.com.kh': { type: 'search', name: 'Google Images' }, - 'images.google.com.kw': { type: 'search', name: 'Google Images' }, - 'images.google.com.lb': { type: 'search', name: 'Google Images' }, - 'images.google.com.lc': { type: 'search', name: 'Google Images' }, - 'images.google.com.ly': { type: 'search', name: 'Google Images' }, - 'images.google.com.mt': { type: 'search', name: 'Google Images' }, - 'images.google.com.mx': { type: 'search', name: 'Google Images' }, - 'images.google.com.my': { type: 'search', name: 'Google Images' }, - 'images.google.com.na': { type: 'search', name: 'Google Images' }, - 'images.google.com.nf': { type: 'search', name: 'Google Images' }, - 'images.google.com.ng': { type: 'search', name: 'Google Images' }, - 'images.google.com.ni': { type: 'search', name: 'Google Images' }, - 'images.google.com.np': { type: 'search', name: 'Google Images' }, - 'images.google.com.om': { type: 'search', name: 'Google Images' }, - 'images.google.com.pa': { type: 'search', name: 'Google Images' }, - 'images.google.com.pe': { type: 'search', name: 'Google Images' }, - 'images.google.com.ph': { type: 'search', name: 'Google Images' }, - 'images.google.com.pk': { type: 'search', name: 'Google Images' }, - 'images.google.com.pr': { type: 'search', name: 'Google Images' }, - 'images.google.com.py': { type: 'search', name: 'Google Images' }, - 'images.google.com.qa': { type: 'search', name: 'Google Images' }, - 'images.google.com.sa': { type: 'search', name: 'Google Images' }, - 'images.google.com.sb': { type: 'search', name: 'Google Images' }, - 'images.google.com.sg': { type: 'search', name: 'Google Images' }, - 'images.google.com.sl': { type: 'search', name: 'Google Images' }, - 'images.google.com.sv': { type: 'search', name: 'Google Images' }, - 'images.google.com.tj': { type: 'search', name: 'Google Images' }, - 'images.google.com.tn': { type: 'search', name: 'Google Images' }, - 'images.google.com.tr': { type: 'search', name: 'Google Images' }, - 'images.google.com.tw': { type: 'search', name: 'Google Images' }, - 'images.google.com.ua': { type: 'search', name: 'Google Images' }, - 'images.google.com.uy': { type: 'search', name: 'Google Images' }, - 'images.google.com.vc': { type: 'search', name: 'Google Images' }, - 'images.google.com.vn': { type: 'search', name: 'Google Images' }, - 'images.google.cv': { type: 'search', name: 'Google Images' }, - 'images.google.cz': { type: 'search', name: 'Google Images' }, - 'images.google.de': { type: 'search', name: 'Google Images' }, - 'images.google.dj': { type: 'search', name: 'Google Images' }, - 'images.google.dk': { type: 'search', name: 'Google Images' }, - 'images.google.dm': { type: 'search', name: 'Google Images' }, - 'images.google.dz': { type: 'search', name: 'Google Images' }, - 'images.google.ee': { type: 'search', name: 'Google Images' }, - 'images.google.es': { type: 'search', name: 'Google Images' }, - 'images.google.fi': { type: 'search', name: 'Google Images' }, - 'images.google.fm': { type: 'search', name: 'Google Images' }, - 'images.google.fr': { type: 'search', name: 'Google Images' }, - 'images.google.ga': { type: 'search', name: 'Google Images' }, - 'images.google.gd': { type: 'search', name: 'Google Images' }, - 'images.google.ge': { type: 'search', name: 'Google Images' }, - 'images.google.gf': { type: 'search', name: 'Google Images' }, - 'images.google.gg': { type: 'search', name: 'Google Images' }, - 'images.google.gl': { type: 'search', name: 'Google Images' }, - 'images.google.gm': { type: 'search', name: 'Google Images' }, - 'images.google.gp': { type: 'search', name: 'Google Images' }, - 'images.google.gr': { type: 'search', name: 'Google Images' }, - 'images.google.gy': { type: 'search', name: 'Google Images' }, - 'images.google.hn': { type: 'search', name: 'Google Images' }, - 'images.google.hr': { type: 'search', name: 'Google Images' }, - 'images.google.ht': { type: 'search', name: 'Google Images' }, - 'images.google.hu': { type: 'search', name: 'Google Images' }, - 'images.google.ie': { type: 'search', name: 'Google Images' }, - 'images.google.im': { type: 'search', name: 'Google Images' }, - 'images.google.io': { type: 'search', name: 'Google Images' }, - 'images.google.iq': { type: 'search', name: 'Google Images' }, - 'images.google.is': { type: 'search', name: 'Google Images' }, - 'images.google.it': { type: 'search', name: 'Google Images' }, - 'images.google.it.ao': { type: 'search', name: 'Google Images' }, - 'images.google.je': { type: 'search', name: 'Google Images' }, - 'images.google.jo': { type: 'search', name: 'Google Images' }, - 'images.google.kg': { type: 'search', name: 'Google Images' }, - 'images.google.ki': { type: 'search', name: 'Google Images' }, - 'images.google.kz': { type: 'search', name: 'Google Images' }, - 'images.google.la': { type: 'search', name: 'Google Images' }, - 'images.google.li': { type: 'search', name: 'Google Images' }, - 'images.google.lk': { type: 'search', name: 'Google Images' }, - 'images.google.lt': { type: 'search', name: 'Google Images' }, - 'images.google.lu': { type: 'search', name: 'Google Images' }, - 'images.google.lv': { type: 'search', name: 'Google Images' }, - 'images.google.md': { type: 'search', name: 'Google Images' }, - 'images.google.me': { type: 'search', name: 'Google Images' }, - 'images.google.mg': { type: 'search', name: 'Google Images' }, - 'images.google.mk': { type: 'search', name: 'Google Images' }, - 'images.google.ml': { type: 'search', name: 'Google Images' }, - 'images.google.mn': { type: 'search', name: 'Google Images' }, - 'images.google.ms': { type: 'search', name: 'Google Images' }, - 'images.google.mu': { type: 'search', name: 'Google Images' }, - 'images.google.mv': { type: 'search', name: 'Google Images' }, - 'images.google.mw': { type: 'search', name: 'Google Images' }, - 'images.google.ne': { type: 'search', name: 'Google Images' }, - 'images.google.nl': { type: 'search', name: 'Google Images' }, - 'images.google.no': { type: 'search', name: 'Google Images' }, - 'images.google.nr': { type: 'search', name: 'Google Images' }, - 'images.google.nu': { type: 'search', name: 'Google Images' }, - 'images.google.pl': { type: 'search', name: 'Google Images' }, - 'images.google.pn': { type: 'search', name: 'Google Images' }, - 'images.google.ps': { type: 'search', name: 'Google Images' }, - 'images.google.pt': { type: 'search', name: 'Google Images' }, - 'images.google.ro': { type: 'search', name: 'Google Images' }, - 'images.google.rs': { type: 'search', name: 'Google Images' }, - 'images.google.ru': { type: 'search', name: 'Google Images' }, - 'images.google.rw': { type: 'search', name: 'Google Images' }, - 'images.google.sc': { type: 'search', name: 'Google Images' }, - 'images.google.se': { type: 'search', name: 'Google Images' }, - 'images.google.sh': { type: 'search', name: 'Google Images' }, - 'images.google.si': { type: 'search', name: 'Google Images' }, - 'images.google.sk': { type: 'search', name: 'Google Images' }, - 'images.google.sm': { type: 'search', name: 'Google Images' }, - 'images.google.sn': { type: 'search', name: 'Google Images' }, - 'images.google.so': { type: 'search', name: 'Google Images' }, - 'images.google.st': { type: 'search', name: 'Google Images' }, - 'images.google.td': { type: 'search', name: 'Google Images' }, - 'images.google.tg': { type: 'search', name: 'Google Images' }, - 'images.google.tk': { type: 'search', name: 'Google Images' }, - 'images.google.tl': { type: 'search', name: 'Google Images' }, - 'images.google.tm': { type: 'search', name: 'Google Images' }, - 'images.google.to': { type: 'search', name: 'Google Images' }, - 'images.google.tt': { type: 'search', name: 'Google Images' }, - 'images.google.us': { type: 'search', name: 'Google Images' }, - 'images.google.vg': { type: 'search', name: 'Google Images' }, - 'images.google.vu': { type: 'search', name: 'Google Images' }, - 'abcsolk.no': { type: 'search', name: 'ABCsøk' }, - 'verden.abcsok.no': { type: 'search', name: 'ABCsøk' }, - 'google.ac/products': { type: 'search', name: 'Google Product Search' }, - 'google.ad/products': { type: 'search', name: 'Google Product Search' }, - 'google.ae/products': { type: 'search', name: 'Google Product Search' }, - 'google.am/products': { type: 'search', name: 'Google Product Search' }, - 'google.as/products': { type: 'search', name: 'Google Product Search' }, - 'google.at/products': { type: 'search', name: 'Google Product Search' }, - 'google.az/products': { type: 'search', name: 'Google Product Search' }, - 'google.ba/products': { type: 'search', name: 'Google Product Search' }, - 'google.be/products': { type: 'search', name: 'Google Product Search' }, - 'google.bf/products': { type: 'search', name: 'Google Product Search' }, - 'google.bg/products': { type: 'search', name: 'Google Product Search' }, - 'google.bi/products': { type: 'search', name: 'Google Product Search' }, - 'google.bj/products': { type: 'search', name: 'Google Product Search' }, - 'google.bs/products': { type: 'search', name: 'Google Product Search' }, - 'google.by/products': { type: 'search', name: 'Google Product Search' }, - 'google.ca/products': { type: 'search', name: 'Google Product Search' }, - 'google.cat/products': { type: 'search', name: 'Google Product Search' }, - 'google.cc/products': { type: 'search', name: 'Google Product Search' }, - 'google.cd/products': { type: 'search', name: 'Google Product Search' }, - 'google.cf/products': { type: 'search', name: 'Google Product Search' }, - 'google.cg/products': { type: 'search', name: 'Google Product Search' }, - 'google.ch/products': { type: 'search', name: 'Google Product Search' }, - 'google.ci/products': { type: 'search', name: 'Google Product Search' }, - 'google.cl/products': { type: 'search', name: 'Google Product Search' }, - 'google.cm/products': { type: 'search', name: 'Google Product Search' }, - 'google.cn/products': { type: 'search', name: 'Google Product Search' }, - 'google.co.bw/products': { type: 'search', name: 'Google Product Search' }, - 'google.co.ck/products': { type: 'search', name: 'Google Product Search' }, - 'google.co.cr/products': { type: 'search', name: 'Google Product Search' }, - 'google.co.id/products': { type: 'search', name: 'Google Product Search' }, - 'google.co.il/products': { type: 'search', name: 'Google Product Search' }, - 'google.co.in/products': { type: 'search', name: 'Google Product Search' }, - 'google.co.jp/products': { type: 'search', name: 'Google Product Search' }, - 'google.co.ke/products': { type: 'search', name: 'Google Product Search' }, - 'google.co.kr/products': { type: 'search', name: 'Google Product Search' }, - 'google.co.ls/products': { type: 'search', name: 'Google Product Search' }, - 'google.co.ma/products': { type: 'search', name: 'Google Product Search' }, - 'google.co.mz/products': { type: 'search', name: 'Google Product Search' }, - 'google.co.nz/products': { type: 'search', name: 'Google Product Search' }, - 'google.co.th/products': { type: 'search', name: 'Google Product Search' }, - 'google.co.tz/products': { type: 'search', name: 'Google Product Search' }, - 'google.co.ug/products': { type: 'search', name: 'Google Product Search' }, - 'google.co.uk/products': { type: 'search', name: 'Google Product Search' }, - 'google.co.uz/products': { type: 'search', name: 'Google Product Search' }, - 'google.co.ve/products': { type: 'search', name: 'Google Product Search' }, - 'google.co.vi/products': { type: 'search', name: 'Google Product Search' }, - 'google.co.za/products': { type: 'search', name: 'Google Product Search' }, - 'google.co.zm/products': { type: 'search', name: 'Google Product Search' }, - 'google.co.zw/products': { type: 'search', name: 'Google Product Search' }, - 'google.com/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.af/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.ag/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.ai/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.ar/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.au/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.bd/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.bh/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.bn/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.bo/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.br/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.by/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.bz/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.co/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.cu/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.cy/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.do/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.ec/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.eg/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.et/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.fj/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.gh/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.gi/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.gt/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.hk/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.jm/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.kh/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.kw/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.lb/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.lc/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.ly/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.mt/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.mx/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.my/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.na/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.nf/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.ng/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.ni/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.np/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.om/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.pa/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.pe/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.ph/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.pk/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.pr/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.py/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.qa/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.sa/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.sb/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.sg/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.sl/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.sv/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.tj/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.tn/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.tr/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.tw/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.ua/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.uy/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.vc/products': { type: 'search', name: 'Google Product Search' }, - 'google.com.vn/products': { type: 'search', name: 'Google Product Search' }, - 'google.cv/products': { type: 'search', name: 'Google Product Search' }, - 'google.cz/products': { type: 'search', name: 'Google Product Search' }, - 'google.de/products': { type: 'search', name: 'Google Product Search' }, - 'google.dj/products': { type: 'search', name: 'Google Product Search' }, - 'google.dk/products': { type: 'search', name: 'Google Product Search' }, - 'google.dm/products': { type: 'search', name: 'Google Product Search' }, - 'google.dz/products': { type: 'search', name: 'Google Product Search' }, - 'google.ee/products': { type: 'search', name: 'Google Product Search' }, - 'google.es/products': { type: 'search', name: 'Google Product Search' }, - 'google.fi/products': { type: 'search', name: 'Google Product Search' }, - 'google.fm/products': { type: 'search', name: 'Google Product Search' }, - 'google.fr/products': { type: 'search', name: 'Google Product Search' }, - 'google.ga/products': { type: 'search', name: 'Google Product Search' }, - 'google.gd/products': { type: 'search', name: 'Google Product Search' }, - 'google.ge/products': { type: 'search', name: 'Google Product Search' }, - 'google.gf/products': { type: 'search', name: 'Google Product Search' }, - 'google.gg/products': { type: 'search', name: 'Google Product Search' }, - 'google.gl/products': { type: 'search', name: 'Google Product Search' }, - 'google.gm/products': { type: 'search', name: 'Google Product Search' }, - 'google.gp/products': { type: 'search', name: 'Google Product Search' }, - 'google.gr/products': { type: 'search', name: 'Google Product Search' }, - 'google.gy/products': { type: 'search', name: 'Google Product Search' }, - 'google.hn/products': { type: 'search', name: 'Google Product Search' }, - 'google.hr/products': { type: 'search', name: 'Google Product Search' }, - 'google.ht/products': { type: 'search', name: 'Google Product Search' }, - 'google.hu/products': { type: 'search', name: 'Google Product Search' }, - 'google.ie/products': { type: 'search', name: 'Google Product Search' }, - 'google.im/products': { type: 'search', name: 'Google Product Search' }, - 'google.io/products': { type: 'search', name: 'Google Product Search' }, - 'google.iq/products': { type: 'search', name: 'Google Product Search' }, - 'google.is/products': { type: 'search', name: 'Google Product Search' }, - 'google.it/products': { type: 'search', name: 'Google Product Search' }, - 'google.it.ao/products': { type: 'search', name: 'Google Product Search' }, - 'google.je/products': { type: 'search', name: 'Google Product Search' }, - 'google.jo/products': { type: 'search', name: 'Google Product Search' }, - 'google.kg/products': { type: 'search', name: 'Google Product Search' }, - 'google.ki/products': { type: 'search', name: 'Google Product Search' }, - 'google.kz/products': { type: 'search', name: 'Google Product Search' }, - 'google.la/products': { type: 'search', name: 'Google Product Search' }, - 'google.li/products': { type: 'search', name: 'Google Product Search' }, - 'google.lk/products': { type: 'search', name: 'Google Product Search' }, - 'google.lt/products': { type: 'search', name: 'Google Product Search' }, - 'google.lu/products': { type: 'search', name: 'Google Product Search' }, - 'google.lv/products': { type: 'search', name: 'Google Product Search' }, - 'google.md/products': { type: 'search', name: 'Google Product Search' }, - 'google.me/products': { type: 'search', name: 'Google Product Search' }, - 'google.mg/products': { type: 'search', name: 'Google Product Search' }, - 'google.mk/products': { type: 'search', name: 'Google Product Search' }, - 'google.ml/products': { type: 'search', name: 'Google Product Search' }, - 'google.mn/products': { type: 'search', name: 'Google Product Search' }, - 'google.ms/products': { type: 'search', name: 'Google Product Search' }, - 'google.mu/products': { type: 'search', name: 'Google Product Search' }, - 'google.mv/products': { type: 'search', name: 'Google Product Search' }, - 'google.mw/products': { type: 'search', name: 'Google Product Search' }, - 'google.ne/products': { type: 'search', name: 'Google Product Search' }, - 'google.nl/products': { type: 'search', name: 'Google Product Search' }, - 'google.no/products': { type: 'search', name: 'Google Product Search' }, - 'google.nr/products': { type: 'search', name: 'Google Product Search' }, - 'google.nu/products': { type: 'search', name: 'Google Product Search' }, - 'google.pl/products': { type: 'search', name: 'Google Product Search' }, - 'google.pn/products': { type: 'search', name: 'Google Product Search' }, - 'google.ps/products': { type: 'search', name: 'Google Product Search' }, - 'google.pt/products': { type: 'search', name: 'Google Product Search' }, - 'google.ro/products': { type: 'search', name: 'Google Product Search' }, - 'google.rs/products': { type: 'search', name: 'Google Product Search' }, - 'google.ru/products': { type: 'search', name: 'Google Product Search' }, - 'google.rw/products': { type: 'search', name: 'Google Product Search' }, - 'google.sc/products': { type: 'search', name: 'Google Product Search' }, - 'google.se/products': { type: 'search', name: 'Google Product Search' }, - 'google.sh/products': { type: 'search', name: 'Google Product Search' }, - 'google.si/products': { type: 'search', name: 'Google Product Search' }, - 'google.sk/products': { type: 'search', name: 'Google Product Search' }, - 'google.sm/products': { type: 'search', name: 'Google Product Search' }, - 'google.sn/products': { type: 'search', name: 'Google Product Search' }, - 'google.so/products': { type: 'search', name: 'Google Product Search' }, - 'google.st/products': { type: 'search', name: 'Google Product Search' }, - 'google.td/products': { type: 'search', name: 'Google Product Search' }, - 'google.tg/products': { type: 'search', name: 'Google Product Search' }, - 'google.tk/products': { type: 'search', name: 'Google Product Search' }, - 'google.tl/products': { type: 'search', name: 'Google Product Search' }, - 'google.tm/products': { type: 'search', name: 'Google Product Search' }, - 'google.to/products': { type: 'search', name: 'Google Product Search' }, - 'google.tt/products': { type: 'search', name: 'Google Product Search' }, - 'google.us/products': { type: 'search', name: 'Google Product Search' }, - 'google.vg/products': { type: 'search', name: 'Google Product Search' }, - 'google.vu/products': { type: 'search', name: 'Google Product Search' }, - 'google.ws/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.ac/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.ad/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.ae/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.am/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.as/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.at/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.az/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.ba/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.be/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.bf/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.bg/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.bi/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.bj/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.bs/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.by/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.ca/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.cat/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.cc/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.cd/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.cf/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.cg/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.ch/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.ci/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.cl/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.cm/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.cn/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.co.bw/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.co.ck/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.co.cr/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.co.id/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.co.il/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.co.in/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.co.jp/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.co.ke/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.co.kr/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.co.ls/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.co.ma/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.co.mz/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.co.nz/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.co.th/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.co.tz/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.co.ug/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.co.uk/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.co.uz/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.co.ve/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.co.vi/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.co.za/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.co.zm/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.co.zw/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.com.af/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.ag/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.ai/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.ar/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.au/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.bd/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.bh/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.bn/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.bo/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.br/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.by/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.bz/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.co/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.cu/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.cy/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.do/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.ec/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.eg/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.et/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.fj/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.gh/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.gi/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.gt/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.hk/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.jm/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.kh/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.kw/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.lb/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.lc/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.ly/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.mt/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.mx/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.my/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.na/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.nf/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.ng/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.ni/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.np/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.om/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.pa/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.pe/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.ph/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.pk/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.pr/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.py/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.qa/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.sa/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.sb/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.sg/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.sl/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.sv/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.tj/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.tn/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.tr/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.tw/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.ua/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.uy/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.vc/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.com.vn/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.cv/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.cz/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.de/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.dj/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.dk/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.dm/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.dz/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.ee/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.es/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.fi/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.fm/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.fr/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.ga/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.gd/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.ge/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.gf/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.gg/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.gl/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.gm/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.gp/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.gr/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.gy/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.hn/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.hr/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.ht/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.hu/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.ie/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.im/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.io/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.iq/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.is/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.it/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.it.ao/products': { - type: 'search', - name: 'Google Product Search', - }, - 'www.google.je/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.jo/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.kg/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.ki/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.kz/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.la/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.li/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.lk/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.lt/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.lu/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.lv/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.md/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.me/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.mg/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.mk/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.ml/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.mn/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.ms/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.mu/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.mv/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.mw/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.ne/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.nl/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.no/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.nr/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.nu/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.pl/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.pn/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.ps/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.pt/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.ro/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.rs/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.ru/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.rw/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.sc/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.se/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.sh/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.si/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.sk/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.sm/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.sn/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.so/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.st/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.td/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.tg/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.tk/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.tl/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.tm/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.to/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.tt/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.us/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.vg/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.vu/products': { type: 'search', name: 'Google Product Search' }, - 'www.google.ws/products': { type: 'search', name: 'Google Product Search' }, - 'www.dasoertliche.de': { type: 'search', name: 'DasOertliche' }, - 'infospace.com': { type: 'search', name: 'InfoSpace' }, - 'dogpile.com': { type: 'search', name: 'InfoSpace' }, - 'www.dogpile.com': { type: 'search', name: 'InfoSpace' }, - 'metacrawler.com': { type: 'search', name: 'InfoSpace' }, - 'webfetch.com': { type: 'search', name: 'InfoSpace' }, - 'webcrawler.com': { type: 'search', name: 'InfoSpace' }, - 'search.kiwee.com': { type: 'search', name: 'InfoSpace' }, - 'isearch.babylon.com': { type: 'search', name: 'InfoSpace' }, - 'start.facemoods.com': { type: 'search', name: 'InfoSpace' }, - 'search.magnetic.com': { type: 'search', name: 'InfoSpace' }, - 'search.searchcompletion.com': { type: 'search', name: 'InfoSpace' }, - 'clusty.com': { type: 'search', name: 'InfoSpace' }, - 'www.weborama.com': { type: 'search', name: 'Weborama' }, - 'search.bluewin.ch': { type: 'search', name: 'Bluewin' }, - 'search.bt.com': { type: 'search', name: 'British Telecommunications' }, - 'www.neti.ee': { type: 'search', name: 'Neti' }, - 'nigma.ru': { type: 'search', name: 'Nigma' }, - 'image.yahoo.cn': { type: 'search', name: 'Yahoo! Images' }, - 'images.search.yahoo.com': { type: 'search', name: 'Yahoo! Images' }, - 'www.exalead.fr': { type: 'search', name: 'Exalead' }, - 'www.exalead.com': { type: 'search', name: 'Exalead' }, - 'www.teoma.com': { type: 'search', name: 'Teoma' }, - 'ko.search.need2find.com': { type: 'search', name: 'Needtofind' }, - 'www.looksmart.com': { type: 'search', name: 'Looksmart' }, - 'inspsearch.com': { type: 'search', name: 'Flyingbird' }, - 'viview.inspsearch.com': { type: 'search', name: 'Flyingbird' }, - 'www.everyclick.com': { type: 'search', name: 'Everyclick' }, - 'szukaj.wp.pl': { type: 'search', name: 'Wirtualna Polska' }, - 'www.toolbarhome.com': { type: 'search', name: 'Toolbarhome' }, - 'vshare.toolbarhome.com': { type: 'search', name: 'Toolbarhome' }, - 'searchalot.com': { type: 'search', name: 'Searchalot' }, - 'yandex.ru': { type: 'search', name: 'Yandex' }, - 'yandex.ua': { type: 'search', name: 'Yandex' }, - 'yandex.com': { type: 'search', name: 'Yandex' }, - 'yandex.by': { type: 'search', name: 'Yandex' }, - 'www.yandex.ru': { type: 'search', name: 'Yandex' }, - 'www.yandex.ua': { type: 'search', name: 'Yandex' }, - 'www.yandex.com': { type: 'search', name: 'Yandex' }, - 'www.yandex.by': { type: 'search', name: 'Yandex' }, - 'clck.yandex.ru': { type: 'search', name: 'Yandex' }, - 'clck.yandex.ua': { type: 'search', name: 'Yandex' }, - 'clck.yandex.com': { type: 'search', name: 'Yandex' }, - 'clck.yandex.by': { type: 'search', name: 'Yandex' }, - 'de.indeed.com': { type: 'search', name: 'Indeed' }, - 'at.indeed.com': { type: 'search', name: 'Indeed' }, - 'fr.indeed.com': { type: 'search', name: 'Indeed' }, - 'it.indeed.com': { type: 'search', name: 'Indeed' }, - 'ch.indeed.com': { type: 'search', name: 'Indeed' }, - 'au.indeed.com': { type: 'search', name: 'Indeed' }, - 'web.canoe.ca': { type: 'search', name: 'canoe.ca' }, - 'websearch.cs.com': { type: 'search', name: 'Compuserve' }, - 'www.blogdigger.com': { type: 'search', name: 'Blogdigger' }, - 'startgoogle.startpagina.nl': { type: 'search', name: 'Startpagina' }, - 'eo.st': { type: 'search', name: 'eo' }, - 'p.zhongsou.com': { type: 'search', name: 'Zhongsou' }, - 'www.toile.com': { type: 'search', name: 'La Toile Du Quebec Via Google' }, - 'web.toile.com': { type: 'search', name: 'La Toile Du Quebec Via Google' }, - 'www.paperball.de': { type: 'search', name: 'Paperball' }, - 'www.stepstone.de': { type: 'search', name: 'StepStone' }, - 'www.stepstone.at': { type: 'search', name: 'StepStone' }, - 'www.stepstone.be': { type: 'search', name: 'StepStone' }, - 'www.stepstone.fr': { type: 'search', name: 'StepStone' }, - 'www.stepstone.nl': { type: 'search', name: 'StepStone' }, - 'www.stepstone.dk': { type: 'search', name: 'StepStone' }, - 'www.stepstone.se': { type: 'search', name: 'StepStone' }, - 'www.jungle-spider.de': { type: 'search', name: 'Jungle Spider' }, - 'search.peoplepc.com': { type: 'search', name: 'PeoplePC' }, - 'thesmartsearch.net': { type: 'search', name: 'The Smart Search' }, - 'www.thesmartsearch.net': { type: 'search', name: 'The Smart Search' }, - 's1.metacrawler.de': { type: 'search', name: 'MetaCrawler.de' }, - 's2.metacrawler.de': { type: 'search', name: 'MetaCrawler.de' }, - 's3.metacrawler.de': { type: 'search', name: 'MetaCrawler.de' }, - 'busca.orange.es': { type: 'search', name: 'Orange' }, - 'search.orange.co.uk': { type: 'search', name: 'Orange' }, - 'lemoteur.orange.fr': { type: 'search', name: 'Orange' }, - 'www.gulesider.no': { type: 'search', name: 'Gule Sider' }, - 'search.i.ua': { type: 'search', name: 'I.ua' }, - 'recherche.francite.com': { type: 'search', name: 'Francite' }, - 'search.tb.ask.com': { type: 'search', name: 'Ask Toolbar' }, - 'search.tut.by': { type: 'search', name: 'Tut.by' }, - 'www.trusted--search.com': { type: 'search', name: 'Trusted-Search' }, - 'search.goo.ne.jp': { type: 'search', name: 'goo' }, - 'ocnsearch.goo.ne.jp': { type: 'search', name: 'goo' }, - 'www.fastbrowsersearch.com': { type: 'search', name: 'Fast Browser Search' }, - 'kununu.com': { type: 'search', name: 'kununu' }, - 'web.volny.cz': { type: 'search', name: 'Volny' }, - 'blogs.icerocket.com': { type: 'search', name: 'Icerockeet' }, - 'buscador.terra.es': { type: 'search', name: 'Terra' }, - 'buscador.terra.cl': { type: 'search', name: 'Terra' }, - 'buscador.terra.com.br': { type: 'search', name: 'Terra' }, - 'amazon.com': { type: 'search', name: 'Amazon' }, - 'www.amazon.com': { type: 'search', name: 'Amazon' }, - 'szukaj.onet.pl': { type: 'search', name: 'Onet' }, - 'digg.com': { type: 'search', name: 'Digg' }, - 'www.abacho.de': { type: 'search', name: 'Abacho' }, - 'www.abacho.com': { type: 'search', name: 'Abacho' }, - 'www.abacho.co.uk': { type: 'search', name: 'Abacho' }, - 'www.se.abacho.com': { type: 'search', name: 'Abacho' }, - 'www.tr.abacho.com': { type: 'search', name: 'Abacho' }, - 'www.abacho.at': { type: 'search', name: 'Abacho' }, - 'www.abacho.fr': { type: 'search', name: 'Abacho' }, - 'www.abacho.es': { type: 'search', name: 'Abacho' }, - 'www.abacho.ch': { type: 'search', name: 'Abacho' }, - 'www.abacho.it': { type: 'search', name: 'Abacho' }, - 'www.maailm.com': { type: 'search', name: 'maailm' }, - 'www.flix.de': { type: 'search', name: 'Flix' }, - 'inbox.com/search/': { type: 'search', name: 'Inbox.com' }, - 'suche.freenet.de': { type: 'search', name: 'Freenet' }, - 'www.suchnase.de': { type: 'search', name: 'Suchnase' }, - 'google.dodo.com.au': { type: 'search', name: 'Dodo' }, - 'blogsearch.google.ac': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.ad': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.ae': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.am': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.as': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.at': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.az': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.ba': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.be': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.bf': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.bg': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.bi': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.bj': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.bs': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.by': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.ca': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.cat': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.cc': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.cd': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.cf': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.cg': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.ch': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.ci': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.cl': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.cm': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.cn': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.co.bw': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.co.ck': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.co.cr': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.co.id': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.co.il': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.co.in': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.co.jp': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.co.ke': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.co.kr': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.co.ls': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.co.ma': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.co.mz': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.co.nz': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.co.th': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.co.tz': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.co.ug': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.co.uk': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.co.uz': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.co.ve': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.co.vi': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.co.za': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.co.zm': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.co.zw': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.af': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.ag': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.ai': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.ar': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.au': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.bd': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.bh': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.bn': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.bo': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.br': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.by': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.bz': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.co': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.cu': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.cy': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.do': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.ec': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.eg': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.et': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.fj': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.gh': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.gi': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.gt': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.hk': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.jm': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.kh': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.kw': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.lb': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.lc': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.ly': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.mt': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.mx': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.my': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.na': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.nf': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.ng': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.ni': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.np': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.om': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.pa': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.pe': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.ph': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.pk': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.pr': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.py': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.qa': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.sa': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.sb': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.sg': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.sl': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.sv': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.tj': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.tn': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.tr': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.tw': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.ua': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.uy': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.vc': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.com.vn': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.cv': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.cz': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.de': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.dj': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.dk': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.dm': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.dz': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.ee': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.es': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.fi': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.fm': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.fr': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.ga': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.gd': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.ge': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.gf': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.gg': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.gl': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.gm': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.gp': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.gr': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.gy': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.hn': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.hr': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.ht': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.hu': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.ie': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.im': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.io': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.iq': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.is': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.it': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.it.ao': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.je': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.jo': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.kg': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.ki': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.kz': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.la': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.li': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.lk': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.lt': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.lu': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.lv': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.md': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.me': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.mg': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.mk': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.ml': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.mn': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.ms': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.mu': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.mv': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.mw': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.ne': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.nl': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.no': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.nr': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.nu': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.pl': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.pn': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.ps': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.pt': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.ro': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.rs': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.ru': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.rw': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.sc': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.se': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.sh': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.si': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.sk': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.sm': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.sn': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.so': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.st': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.td': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.tg': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.tk': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.tl': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.tm': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.to': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.tt': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.us': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.vg': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.vu': { type: 'search', name: 'Google Blogsearch' }, - 'blogsearch.google.ws': { type: 'search', name: 'Google Blogsearch' }, - 'poisk.ru': { type: 'search', name: 'Poisk.ru' }, - 'www.sharelook.fr': { type: 'search', name: 'Sharelook' }, - 'www.finderoo.com': { type: 'search', name: 'Finderoo' }, - 'www.najdi.si': { type: 'search', name: 'Najdi' }, - 'www.picsearch.com': { type: 'search', name: 'Picsearch' }, - 'mail.ru': { type: 'search', name: 'Mail.ru' }, - 'm.mail.ru': { type: 'search', name: 'Mail.ru' }, - 'go.mail.ru': { type: 'search', name: 'Mail.ru' }, - 'alexa.com': { type: 'search', name: 'Alexa' }, - 'search.toolbars.alexa.com': { type: 'search', name: 'Alexa' }, - 'meta.rrzn.uni-hannover.de': { type: 'search', name: 'Metager' }, - 'www.metager.de': { type: 'search', name: 'Metager' }, - 'technorati.com': { type: 'search', name: 'Technorati' }, - 'searches.globososo.com': { type: 'search', name: 'Globososo' }, - 'search.globososo.com': { type: 'search', name: 'Globososo' }, - 'search.www.ee': { type: 'search', name: 'WWW' }, - 'www.trouvez.com': { type: 'search', name: 'Trouvez.com' }, - 'ixquick.com': { type: 'search', name: 'IXquick' }, - 'www.eu.ixquick.com': { type: 'search', name: 'IXquick' }, - 'ixquick.de': { type: 'search', name: 'IXquick' }, - 'www.ixquick.de': { type: 'search', name: 'IXquick' }, - 'us.ixquick.com': { type: 'search', name: 'IXquick' }, - 's1.us.ixquick.com': { type: 'search', name: 'IXquick' }, - 's2.us.ixquick.com': { type: 'search', name: 'IXquick' }, - 's3.us.ixquick.com': { type: 'search', name: 'IXquick' }, - 's4.us.ixquick.com': { type: 'search', name: 'IXquick' }, - 's5.us.ixquick.com': { type: 'search', name: 'IXquick' }, - 'eu.ixquick.com': { type: 'search', name: 'IXquick' }, - 's8-eu.ixquick.com': { type: 'search', name: 'IXquick' }, - 's1-eu.ixquick.de': { type: 'search', name: 'IXquick' }, - 'image.search.naver.com': { type: 'search', name: 'Naver Images' }, - 'imagesearch.naver.com': { type: 'search', name: 'Naver Images' }, - 'www.zapmeta.com': { type: 'search', name: 'Zapmeta' }, - 'www.zapmeta.nl': { type: 'search', name: 'Zapmeta' }, - 'www.zapmeta.de': { type: 'search', name: 'Zapmeta' }, - 'uk.zapmeta.com': { type: 'search', name: 'Zapmeta' }, - 'search.yippy.com': { type: 'search', name: 'Yippy' }, - 'pesquisa.clix.pt': { type: 'search', name: 'Clix' }, - 'www.walhello.info': { type: 'search', name: 'Walhello' }, - 'www.walhello.com': { type: 'search', name: 'Walhello' }, - 'www.walhello.de': { type: 'search', name: 'Walhello' }, - 'www.walhello.nl': { type: 'search', name: 'Walhello' }, - 'meta.ua': { type: 'search', name: 'Meta' }, - 'www.skynet.be': { type: 'search', name: 'Skynet' }, - 'www.searchy.co.uk': { type: 'search', name: 'Searchy' }, - 'search.findwide.com': { type: 'search', name: 'Findwide' }, - 'www.websearch.com': { type: 'search', name: 'WebSearch' }, - 'nova.rambler.ru': { type: 'search', name: 'Rambler' }, - 'www.latne.lv': { type: 'search', name: 'Latne' }, - 'mysearch.com': { type: 'search', name: 'MySearch' }, - 'www.mysearch.com': { type: 'search', name: 'MySearch' }, - 'ms114.mysearch.com': { type: 'search', name: 'MySearch' }, - 'ms146.mysearch.com': { type: 'search', name: 'MySearch' }, - 'kf.mysearch.myway.com': { type: 'search', name: 'MySearch' }, - 'ki.mysearch.myway.com': { type: 'search', name: 'MySearch' }, - 'search.myway.com': { type: 'search', name: 'MySearch' }, - 'search.mywebsearch.com': { type: 'search', name: 'MySearch' }, - 'www.cuil.com': { type: 'search', name: 'Cuil' }, - 'www.tixuma.de': { type: 'search', name: 'Tixuma' }, - 'pesquisa.sapo.pt': { type: 'search', name: 'Sapo' }, - 'www.gnadenmeer.de': { type: 'search', name: 'Gnadenmeer' }, - 'search.lilo.org': { type: 'search', name: 'Lilo' }, - 'search.naver.com': { type: 'search', name: 'Naver' }, - 'www.zoeken.nl': { type: 'search', name: 'Zoeken' }, - 'www.startsiden.no': { type: 'search', name: 'Startsiden' }, - 'search.yam.com': { type: 'search', name: 'Yam' }, - 'www.eniro.se': { type: 'search', name: 'Eniro' }, - 'apollo7.de': { type: 'search', name: 'APOLL07' }, - 'cgi.search.biglobe.ne.jp': { type: 'search', name: 'Biglobe' }, - 'www.mozbot.fr': { type: 'search', name: 'Mozbot' }, - 'www.mozbot.co.uk': { type: 'search', name: 'Mozbot' }, - 'www.mozbot.com': { type: 'search', name: 'Mozbot' }, - 'www.icq.com': { type: 'search', name: 'ICQ' }, - 'search.icq.com': { type: 'search', name: 'ICQ' }, - 'www.baidu.com': { type: 'search', name: 'Baidu' }, - 'www1.baidu.com': { type: 'search', name: 'Baidu' }, - 'zhidao.baidu.com': { type: 'search', name: 'Baidu' }, - 'tieba.baidu.com': { type: 'search', name: 'Baidu' }, - 'news.baidu.com': { type: 'search', name: 'Baidu' }, - 'web.gougou.com': { type: 'search', name: 'Baidu' }, - 'm.baidu.com': { type: 'search', name: 'Baidu' }, - 'search.conduit.com': { type: 'search', name: 'Conduit' }, - 'www.vindex.nl': { type: 'search', name: 'Vindex' }, - 'search.vindex.nl': { type: 'search', name: 'Vindex' }, - 'search.babylon.com': { type: 'search', name: 'Babylon' }, - 'searchassist.babylon.com': { type: 'search', name: 'Babylon' }, - 'www.trovarapido.com': { type: 'search', name: 'TrovaRapido' }, - 'search.winamp.com': { type: 'search', name: 'Winamp' }, - 'www.suchmaschine.com': { type: 'search', name: 'Suchmaschine.com' }, - 'search.lycos.com': { type: 'search', name: 'Lycos' }, - 'www.lycos.com': { type: 'search', name: 'Lycos' }, - 'lycos.com': { type: 'search', name: 'Lycos' }, - 'www.vinden.nl': { type: 'search', name: 'Vinden' }, - 'www.altavista.com': { type: 'search', name: 'Altavista' }, - 'search.altavista.com': { type: 'search', name: 'Altavista' }, - 'listings.altavista.com': { type: 'search', name: 'Altavista' }, - 'altavista.de': { type: 'search', name: 'Altavista' }, - 'altavista.fr': { type: 'search', name: 'Altavista' }, - 'be-nl.altavista.com': { type: 'search', name: 'Altavista' }, - 'be-fr.altavista.com': { type: 'search', name: 'Altavista' }, - 'dmoz.org': { type: 'search', name: 'dmoz' }, - 'editors.dmoz.org': { type: 'search', name: 'dmoz' }, - 'ecosia.org': { type: 'search', name: 'Ecosia' }, - 'maxwebsearch.com': { type: 'search', name: 'Maxwebsearch' }, - 'www.euroseek.com': { type: 'search', name: 'Euroseek' }, - 'www.qwant.com': { type: 'search', name: 'Qwant' }, - 'lite.qwant.com': { type: 'search', name: 'Qwant' }, - 'www.x-recherche.com': { type: 'search', name: 'X-recherche' }, - 'images.yandex.ru': { type: 'search', name: 'Yandex Images' }, - 'images.yandex.ua': { type: 'search', name: 'Yandex Images' }, - 'images.yandex.com': { type: 'search', name: 'Yandex Images' }, - 'images.yandex.by': { type: 'search', name: 'Yandex Images' }, - 'suche.gmx.net': { type: 'search', name: 'GMX' }, - 'daemon-search.com': { type: 'search', name: 'Daemon search' }, - 'my.daemon-search.com': { type: 'search', name: 'Daemon search' }, - 'so.m.sm.cn': { type: 'search', name: 'Shenma' }, - 'yz.m.sm.cn': { type: 'search', name: 'Shenma' }, - 'm.sm.cn': { type: 'search', name: 'Shenma' }, - 'quark.sm.cn': { type: 'search', name: 'Shenma' }, - 'm.sp.sm.cn': { type: 'search', name: 'Shenma' }, - 'm.yz2.sm.cn': { type: 'search', name: 'Shenma' }, - 'm.yz.sm.cn': { type: 'search', name: 'Shenma' }, - 'www.firstsfind.com': { type: 'search', name: 'Firstfind' }, - 'www.crawler.com': { type: 'search', name: 'Crawler' }, - 'holmes.ge': { type: 'search', name: 'Holmes' }, - 'www.charter.net': { type: 'search', name: 'Charter' }, - 'www.ilse.nl': { type: 'search', name: 'Ilse' }, - 'search.earthlink.net': { type: 'search', name: 'earthlink' }, - 'www.qualigo.at': { type: 'search', name: 'Qualigo' }, - 'www.qualigo.ch': { type: 'search', name: 'Qualigo' }, - 'www.qualigo.de': { type: 'search', name: 'Qualigo' }, - 'www.qualigo.nl': { type: 'search', name: 'Qualigo' }, - 'ariadna.elmundo.es': { type: 'search', name: 'El Mundo' }, - 'metager2.de': { type: 'search', name: 'Metager2' }, - 'forestle.org': { type: 'search', name: 'Forestle' }, - 'www.forestle.org': { type: 'search', name: 'Forestle' }, - 'forestle.mobi': { type: 'search', name: 'Forestle' }, - 'www.search.ch': { type: 'search', name: 'Search.ch' }, - 'liveinternet.ru': { type: 'search', name: 'Liveinternet' }, - 'www.meinestadt.de': { type: 'search', name: 'Meinestadt' }, - 'www.fresh-weather.com': { type: 'search', name: 'Freshweather' }, - 'www.alltheweb.com': { type: 'search', name: 'AllTheWeb' }, - 'coccoc.com': { type: 'search', name: 'Coccoc' }, - 'search.snapdo.com': { type: 'search', name: 'Snapdo' }, - 'search.ukr.net': { type: 'search', name: 'UKR.net' }, - 'www3.zoek.nl': { type: 'search', name: 'Zoek' }, - 'search.daum.net': { type: 'search', name: 'Daum' }, - 'www.marktplaats.nl': { type: 'search', name: 'Marktplaats' }, - 'suche.info': { type: 'search', name: 'suche.info' }, - 'news.google.ac': { type: 'search', name: 'Google News' }, - 'news.google.ad': { type: 'search', name: 'Google News' }, - 'news.google.ae': { type: 'search', name: 'Google News' }, - 'news.google.am': { type: 'search', name: 'Google News' }, - 'news.google.as': { type: 'search', name: 'Google News' }, - 'news.google.at': { type: 'search', name: 'Google News' }, - 'news.google.az': { type: 'search', name: 'Google News' }, - 'news.google.ba': { type: 'search', name: 'Google News' }, - 'news.google.be': { type: 'search', name: 'Google News' }, - 'news.google.bf': { type: 'search', name: 'Google News' }, - 'news.google.bg': { type: 'search', name: 'Google News' }, - 'news.google.bi': { type: 'search', name: 'Google News' }, - 'news.google.bj': { type: 'search', name: 'Google News' }, - 'news.google.bs': { type: 'search', name: 'Google News' }, - 'news.google.by': { type: 'search', name: 'Google News' }, - 'news.google.ca': { type: 'search', name: 'Google News' }, - 'news.google.cat': { type: 'search', name: 'Google News' }, - 'news.google.cc': { type: 'search', name: 'Google News' }, - 'news.google.cd': { type: 'search', name: 'Google News' }, - 'news.google.cf': { type: 'search', name: 'Google News' }, - 'news.google.cg': { type: 'search', name: 'Google News' }, - 'news.google.ch': { type: 'search', name: 'Google News' }, - 'news.google.ci': { type: 'search', name: 'Google News' }, - 'news.google.cl': { type: 'search', name: 'Google News' }, - 'news.google.cm': { type: 'search', name: 'Google News' }, - 'news.google.cn': { type: 'search', name: 'Google News' }, - 'news.google.co.bw': { type: 'search', name: 'Google News' }, - 'news.google.co.ck': { type: 'search', name: 'Google News' }, - 'news.google.co.cr': { type: 'search', name: 'Google News' }, - 'news.google.co.id': { type: 'search', name: 'Google News' }, - 'news.google.co.il': { type: 'search', name: 'Google News' }, - 'news.google.co.in': { type: 'search', name: 'Google News' }, - 'news.google.co.jp': { type: 'search', name: 'Google News' }, - 'news.google.co.ke': { type: 'search', name: 'Google News' }, - 'news.google.co.kr': { type: 'search', name: 'Google News' }, - 'news.google.co.ls': { type: 'search', name: 'Google News' }, - 'news.google.co.ma': { type: 'search', name: 'Google News' }, - 'news.google.co.mz': { type: 'search', name: 'Google News' }, - 'news.google.co.nz': { type: 'search', name: 'Google News' }, - 'news.google.co.th': { type: 'search', name: 'Google News' }, - 'news.google.co.tz': { type: 'search', name: 'Google News' }, - 'news.google.co.ug': { type: 'search', name: 'Google News' }, - 'news.google.co.uk': { type: 'search', name: 'Google News' }, - 'news.google.co.uz': { type: 'search', name: 'Google News' }, - 'news.google.co.ve': { type: 'search', name: 'Google News' }, - 'news.google.co.vi': { type: 'search', name: 'Google News' }, - 'news.google.co.za': { type: 'search', name: 'Google News' }, - 'news.google.co.zm': { type: 'search', name: 'Google News' }, - 'news.google.co.zw': { type: 'search', name: 'Google News' }, - 'news.google.com': { type: 'search', name: 'Google News' }, - 'news.google.com.af': { type: 'search', name: 'Google News' }, - 'news.google.com.ag': { type: 'search', name: 'Google News' }, - 'news.google.com.ai': { type: 'search', name: 'Google News' }, - 'news.google.com.ar': { type: 'search', name: 'Google News' }, - 'news.google.com.au': { type: 'search', name: 'Google News' }, - 'news.google.com.bd': { type: 'search', name: 'Google News' }, - 'news.google.com.bh': { type: 'search', name: 'Google News' }, - 'news.google.com.bn': { type: 'search', name: 'Google News' }, - 'news.google.com.bo': { type: 'search', name: 'Google News' }, - 'news.google.com.br': { type: 'search', name: 'Google News' }, - 'news.google.com.by': { type: 'search', name: 'Google News' }, - 'news.google.com.bz': { type: 'search', name: 'Google News' }, - 'news.google.com.co': { type: 'search', name: 'Google News' }, - 'news.google.com.cu': { type: 'search', name: 'Google News' }, - 'news.google.com.cy': { type: 'search', name: 'Google News' }, - 'news.google.com.do': { type: 'search', name: 'Google News' }, - 'news.google.com.ec': { type: 'search', name: 'Google News' }, - 'news.google.com.eg': { type: 'search', name: 'Google News' }, - 'news.google.com.et': { type: 'search', name: 'Google News' }, - 'news.google.com.fj': { type: 'search', name: 'Google News' }, - 'news.google.com.gh': { type: 'search', name: 'Google News' }, - 'news.google.com.gi': { type: 'search', name: 'Google News' }, - 'news.google.com.gt': { type: 'search', name: 'Google News' }, - 'news.google.com.hk': { type: 'search', name: 'Google News' }, - 'news.google.com.jm': { type: 'search', name: 'Google News' }, - 'news.google.com.kh': { type: 'search', name: 'Google News' }, - 'news.google.com.kw': { type: 'search', name: 'Google News' }, - 'news.google.com.lb': { type: 'search', name: 'Google News' }, - 'news.google.com.lc': { type: 'search', name: 'Google News' }, - 'news.google.com.ly': { type: 'search', name: 'Google News' }, - 'news.google.com.mt': { type: 'search', name: 'Google News' }, - 'news.google.com.mx': { type: 'search', name: 'Google News' }, - 'news.google.com.my': { type: 'search', name: 'Google News' }, - 'news.google.com.na': { type: 'search', name: 'Google News' }, - 'news.google.com.nf': { type: 'search', name: 'Google News' }, - 'news.google.com.ng': { type: 'search', name: 'Google News' }, - 'news.google.com.ni': { type: 'search', name: 'Google News' }, - 'news.google.com.np': { type: 'search', name: 'Google News' }, - 'news.google.com.om': { type: 'search', name: 'Google News' }, - 'news.google.com.pa': { type: 'search', name: 'Google News' }, - 'news.google.com.pe': { type: 'search', name: 'Google News' }, - 'news.google.com.ph': { type: 'search', name: 'Google News' }, - 'news.google.com.pk': { type: 'search', name: 'Google News' }, - 'news.google.com.pr': { type: 'search', name: 'Google News' }, - 'news.google.com.py': { type: 'search', name: 'Google News' }, - 'news.google.com.qa': { type: 'search', name: 'Google News' }, - 'news.google.com.sa': { type: 'search', name: 'Google News' }, - 'news.google.com.sb': { type: 'search', name: 'Google News' }, - 'news.google.com.sg': { type: 'search', name: 'Google News' }, - 'news.google.com.sl': { type: 'search', name: 'Google News' }, - 'news.google.com.sv': { type: 'search', name: 'Google News' }, - 'news.google.com.tj': { type: 'search', name: 'Google News' }, - 'news.google.com.tn': { type: 'search', name: 'Google News' }, - 'news.google.com.tr': { type: 'search', name: 'Google News' }, - 'news.google.com.tw': { type: 'search', name: 'Google News' }, - 'news.google.com.ua': { type: 'search', name: 'Google News' }, - 'news.google.com.uy': { type: 'search', name: 'Google News' }, - 'news.google.com.vc': { type: 'search', name: 'Google News' }, - 'news.google.com.vn': { type: 'search', name: 'Google News' }, - 'news.google.cv': { type: 'search', name: 'Google News' }, - 'news.google.cz': { type: 'search', name: 'Google News' }, - 'news.google.de': { type: 'search', name: 'Google News' }, - 'news.google.dj': { type: 'search', name: 'Google News' }, - 'news.google.dk': { type: 'search', name: 'Google News' }, - 'news.google.dm': { type: 'search', name: 'Google News' }, - 'news.google.dz': { type: 'search', name: 'Google News' }, - 'news.google.ee': { type: 'search', name: 'Google News' }, - 'news.google.es': { type: 'search', name: 'Google News' }, - 'news.google.fi': { type: 'search', name: 'Google News' }, - 'news.google.fm': { type: 'search', name: 'Google News' }, - 'news.google.fr': { type: 'search', name: 'Google News' }, - 'news.google.ga': { type: 'search', name: 'Google News' }, - 'news.google.gd': { type: 'search', name: 'Google News' }, - 'news.google.ge': { type: 'search', name: 'Google News' }, - 'news.google.gf': { type: 'search', name: 'Google News' }, - 'news.google.gg': { type: 'search', name: 'Google News' }, - 'news.google.gl': { type: 'search', name: 'Google News' }, - 'news.google.gm': { type: 'search', name: 'Google News' }, - 'news.google.gp': { type: 'search', name: 'Google News' }, - 'news.google.gr': { type: 'search', name: 'Google News' }, - 'news.google.gy': { type: 'search', name: 'Google News' }, - 'news.google.hn': { type: 'search', name: 'Google News' }, - 'news.google.hr': { type: 'search', name: 'Google News' }, - 'news.google.ht': { type: 'search', name: 'Google News' }, - 'news.google.hu': { type: 'search', name: 'Google News' }, - 'news.google.ie': { type: 'search', name: 'Google News' }, - 'news.google.im': { type: 'search', name: 'Google News' }, - 'news.google.io': { type: 'search', name: 'Google News' }, - 'news.google.iq': { type: 'search', name: 'Google News' }, - 'news.google.is': { type: 'search', name: 'Google News' }, - 'news.google.it': { type: 'search', name: 'Google News' }, - 'news.google.it.ao': { type: 'search', name: 'Google News' }, - 'news.google.je': { type: 'search', name: 'Google News' }, - 'news.google.jo': { type: 'search', name: 'Google News' }, - 'news.google.kg': { type: 'search', name: 'Google News' }, - 'news.google.ki': { type: 'search', name: 'Google News' }, - 'news.google.kz': { type: 'search', name: 'Google News' }, - 'news.google.la': { type: 'search', name: 'Google News' }, - 'news.google.li': { type: 'search', name: 'Google News' }, - 'news.google.lk': { type: 'search', name: 'Google News' }, - 'news.google.lt': { type: 'search', name: 'Google News' }, - 'news.google.lu': { type: 'search', name: 'Google News' }, - 'news.google.lv': { type: 'search', name: 'Google News' }, - 'news.google.md': { type: 'search', name: 'Google News' }, - 'news.google.me': { type: 'search', name: 'Google News' }, - 'news.google.mg': { type: 'search', name: 'Google News' }, - 'news.google.mk': { type: 'search', name: 'Google News' }, - 'news.google.ml': { type: 'search', name: 'Google News' }, - 'news.google.mn': { type: 'search', name: 'Google News' }, - 'news.google.ms': { type: 'search', name: 'Google News' }, - 'news.google.mu': { type: 'search', name: 'Google News' }, - 'news.google.mv': { type: 'search', name: 'Google News' }, - 'news.google.mw': { type: 'search', name: 'Google News' }, - 'news.google.ne': { type: 'search', name: 'Google News' }, - 'news.google.nl': { type: 'search', name: 'Google News' }, - 'news.google.no': { type: 'search', name: 'Google News' }, - 'news.google.nr': { type: 'search', name: 'Google News' }, - 'news.google.nu': { type: 'search', name: 'Google News' }, - 'news.google.pl': { type: 'search', name: 'Google News' }, - 'news.google.pn': { type: 'search', name: 'Google News' }, - 'news.google.ps': { type: 'search', name: 'Google News' }, - 'news.google.pt': { type: 'search', name: 'Google News' }, - 'news.google.ro': { type: 'search', name: 'Google News' }, - 'news.google.rs': { type: 'search', name: 'Google News' }, - 'news.google.ru': { type: 'search', name: 'Google News' }, - 'news.google.rw': { type: 'search', name: 'Google News' }, - 'news.google.sc': { type: 'search', name: 'Google News' }, - 'news.google.se': { type: 'search', name: 'Google News' }, - 'news.google.sh': { type: 'search', name: 'Google News' }, - 'news.google.si': { type: 'search', name: 'Google News' }, - 'news.google.sk': { type: 'search', name: 'Google News' }, - 'news.google.sm': { type: 'search', name: 'Google News' }, - 'news.google.sn': { type: 'search', name: 'Google News' }, - 'news.google.so': { type: 'search', name: 'Google News' }, - 'news.google.st': { type: 'search', name: 'Google News' }, - 'news.google.td': { type: 'search', name: 'Google News' }, - 'news.google.tg': { type: 'search', name: 'Google News' }, - 'news.google.tk': { type: 'search', name: 'Google News' }, - 'news.google.tl': { type: 'search', name: 'Google News' }, - 'news.google.tm': { type: 'search', name: 'Google News' }, - 'news.google.to': { type: 'search', name: 'Google News' }, - 'news.google.tt': { type: 'search', name: 'Google News' }, - 'news.google.us': { type: 'search', name: 'Google News' }, - 'news.google.vg': { type: 'search', name: 'Google News' }, - 'news.google.vu': { type: 'search', name: 'Google News' }, - 'news.google.ws': { type: 'search', name: 'Google News' }, - 'zoohoo.cz': { type: 'search', name: 'Zoohoo' }, - 'search.seznam.cz': { type: 'search', name: 'Seznam' }, - 'online.no': { type: 'search', name: 'Online.no' }, - 'www.eurip.com': { type: 'search', name: 'Eurip' }, - 'all.by': { type: 'search', name: 'all.by' }, - 'search.rr.com': { type: 'search', name: 'Road Runner Search' }, - 'www.1881.no': { type: 'search', name: 'Opplysningen 1881' }, - 'www.yougoo.fr': { type: 'search', name: 'YouGoo' }, - 'bing.com/images/search': { type: 'search', name: 'Bing Images' }, - 'www.bing.com/images/search': { type: 'search', name: 'Bing Images' }, - 'geona.net': { type: 'search', name: 'Geona' }, - 'search.nate.com': { type: 'search', name: 'Nate' }, - 'www.searchthis.com': { type: 'search', name: 'Search This' }, - 'duckduckgo.com': { type: 'search', name: 'DuckDuckGo' }, - 'www.monster.be': { type: 'search', name: 'Monster' }, - 'www.monster.cz': { type: 'search', name: 'Monster' }, - 'www.monster.de': { type: 'search', name: 'Monster' }, - 'www.monster.fi': { type: 'search', name: 'Monster' }, - 'www.monster.fr': { type: 'search', name: 'Monster' }, - 'www.monster.ie': { type: 'search', name: 'Monster' }, - 'www.monster.it': { type: 'search', name: 'Monster' }, - 'www.monster.lu': { type: 'search', name: 'Monster' }, - 'www.monster.ch': { type: 'search', name: 'Monster' }, - 'www.monster.co.uk': { type: 'search', name: 'Monster' }, - 'www.hotbot.com': { type: 'search', name: 'Hotbot' }, - 'www.kvasir.no': { type: 'search', name: 'Kvasir' }, - 'www2.austronaut.at': { type: 'search', name: 'Austronaut' }, - 'www1.astronaut.at': { type: 'search', name: 'Austronaut' }, - 'sosodesktop.com': { type: 'search', name: 'SoSoDesk' }, - 'search.sosodesktop.com': { type: 'search', name: 'SoSoDesk' }, - 'search.excite.it': { type: 'search', name: 'Excite' }, - 'search.excite.fr': { type: 'search', name: 'Excite' }, - 'search.excite.de': { type: 'search', name: 'Excite' }, - 'search.excite.co.uk': { type: 'search', name: 'Excite' }, - 'serach.excite.es': { type: 'search', name: 'Excite' }, - 'search.excite.nl': { type: 'search', name: 'Excite' }, - 'msxml.excite.com': { type: 'search', name: 'Excite' }, - 'www.excite.co.jp': { type: 'search', name: 'Excite' }, - 'search.1and1.com': { type: 'search', name: '1&1' }, - 'search.qip.ru': { type: 'search', name: 'qip' }, - 'search.certified-toolbar.com': { type: 'search', name: 'Certified-Toolbar' }, - 'search.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'ar.search.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'ar.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'au.search.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'au.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'br.search.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'br.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'ca.search.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'ca.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'cade.searchde.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'cade.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'chinese.searchinese.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'chinese.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'cn.search.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'cn.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'de.search.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'de.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'dk.search.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'dk.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'es.search.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'es.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'espanol.searchpanol.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'espanol.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'fr.search.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'fr.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'hk.search.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'hk.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'ie.search.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'ie.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'in.search.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'in.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'it.search.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'it.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'kr.search.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'kr.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'mx.search.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'mx.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'no.search.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'no.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'nz.search.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'nz.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'one.cn.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'one.searchn.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'qc.search.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'qc.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'ru.search.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'ru.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'se.search.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'se.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'search.searcharch.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'tw.search.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'tw.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'uk.search.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'uk.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'us.search.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'us.yahoo.com': { type: 'search', name: 'Yahoo!' }, - 'www.yahoo.co.jp': { type: 'search', name: 'Yahoo!' }, - 'search.yahoo.co.jp': { type: 'search', name: 'Yahoo!' }, - 'www.cercato.it': { type: 'search', name: 'Yahoo!' }, - 'search.offerbox.com': { type: 'search', name: 'Yahoo!' }, - 'ys.mirostart.com': { type: 'search', name: 'Yahoo!' }, - 'www.url.org': { type: 'search', name: 'URL.ORGanizier' }, - 'www.witch.de': { type: 'search', name: 'Witch' }, - 'www.mister-wong.com': { type: 'search', name: 'Mister Wong' }, - 'www.mister-wong.de': { type: 'search', name: 'Mister Wong' }, - 'sm.aport.ru': { type: 'search', name: 'Aport' }, - 'suche.web.de': { type: 'search', name: 'Web.de' }, - 'ask.com': { type: 'search', name: 'Ask' }, - 'www.ask.com': { type: 'search', name: 'Ask' }, - 'web.ask.com': { type: 'search', name: 'Ask' }, - 'int.ask.com': { type: 'search', name: 'Ask' }, - 'mws.ask.com': { type: 'search', name: 'Ask' }, - 'uk.ask.com': { type: 'search', name: 'Ask' }, - 'images.ask.com': { type: 'search', name: 'Ask' }, - 'ask.reference.com': { type: 'search', name: 'Ask' }, - 'www.askkids.com': { type: 'search', name: 'Ask' }, - 'iwon.ask.com': { type: 'search', name: 'Ask' }, - 'www.ask.co.uk': { type: 'search', name: 'Ask' }, - 'www.qbyrd.com': { type: 'search', name: 'Ask' }, - 'search-results.com': { type: 'search', name: 'Ask' }, - 'uk.search-results.com': { type: 'search', name: 'Ask' }, - 'www.search-results.com': { type: 'search', name: 'Ask' }, - 'int.search-results.com': { type: 'search', name: 'Ask' }, - 'serach.centrum.cz': { type: 'search', name: 'Centrum' }, - 'morfeo.centrum.cz': { type: 'search', name: 'Centrum' }, - 'bing.com': { type: 'search', name: 'Bing' }, - 'www.bing.com': { type: 'search', name: 'Bing' }, - 'msnbc.msn.com': { type: 'search', name: 'Bing' }, - 'dizionario.it.msn.com': { type: 'search', name: 'Bing' }, - 'cc.bingj.com': { type: 'search', name: 'Bing' }, - 'm.bing.com': { type: 'search', name: 'Bing' }, - 'video.google.com': { type: 'search', name: 'Google Video' }, - 'otsing.delfi.ee': { type: 'search', name: 'Delfi' }, - 'blekko.com': { type: 'search', name: 'blekko' }, - 'jyxo.1188.cz': { type: 'search', name: 'Jyxo' }, - 'www.kataweb.it': { type: 'search', name: 'Kataweb' }, - 'busca.uol.com.br': { type: 'search', name: 'uol.com.br' }, - 'arianna.libero.it': { type: 'search', name: 'Arianna' }, - 'www.arianna.com': { type: 'search', name: 'Arianna' }, - 'www.mamma.com': { type: 'search', name: 'Mamma' }, - 'mamma75.mamma.com': { type: 'search', name: 'Mamma' }, - 'www.yatedo.com': { type: 'search', name: 'Yatedo' }, - 'www.yatedo.fr': { type: 'search', name: 'Yatedo' }, - 'www.twingly.com': { type: 'search', name: 'Twingly' }, - 'smart.delfi.lv': { type: 'search', name: 'Delfi latvia' }, - 'www.pricerunner.co.uk': { type: 'search', name: 'PriceRunner' }, - 'websearch.rakuten.co.jp': { type: 'search', name: 'Rakuten' }, - 'www.google.com': { type: 'search', name: 'Google' }, - 'www.google.ac': { type: 'search', name: 'Google' }, - 'www.google.ad': { type: 'search', name: 'Google' }, - 'www.google.com.af': { type: 'search', name: 'Google' }, - 'www.google.com.ag': { type: 'search', name: 'Google' }, - 'www.google.com.ai': { type: 'search', name: 'Google' }, - 'www.google.am': { type: 'search', name: 'Google' }, - 'www.google.it.ao': { type: 'search', name: 'Google' }, - 'www.google.com.ar': { type: 'search', name: 'Google' }, - 'www.google.as': { type: 'search', name: 'Google' }, - 'www.google.at': { type: 'search', name: 'Google' }, - 'www.google.com.au': { type: 'search', name: 'Google' }, - 'www.google.az': { type: 'search', name: 'Google' }, - 'www.google.ba': { type: 'search', name: 'Google' }, - 'www.google.com.bd': { type: 'search', name: 'Google' }, - 'www.google.be': { type: 'search', name: 'Google' }, - 'www.google.bf': { type: 'search', name: 'Google' }, - 'www.google.bg': { type: 'search', name: 'Google' }, - 'www.google.com.bh': { type: 'search', name: 'Google' }, - 'www.google.bi': { type: 'search', name: 'Google' }, - 'www.google.bj': { type: 'search', name: 'Google' }, - 'www.google.com.bn': { type: 'search', name: 'Google' }, - 'www.google.com.bo': { type: 'search', name: 'Google' }, - 'www.google.com.br': { type: 'search', name: 'Google' }, - 'www.google.bs': { type: 'search', name: 'Google' }, - 'www.google.co.bw': { type: 'search', name: 'Google' }, - 'www.google.com.by': { type: 'search', name: 'Google' }, - 'www.google.by': { type: 'search', name: 'Google' }, - 'www.google.com.bz': { type: 'search', name: 'Google' }, - 'www.google.ca': { type: 'search', name: 'Google' }, - 'www.google.com.kh': { type: 'search', name: 'Google' }, - 'www.google.cc': { type: 'search', name: 'Google' }, - 'www.google.cd': { type: 'search', name: 'Google' }, - 'www.google.cf': { type: 'search', name: 'Google' }, - 'www.google.cat': { type: 'search', name: 'Google' }, - 'www.google.cg': { type: 'search', name: 'Google' }, - 'www.google.ch': { type: 'search', name: 'Google' }, - 'www.google.ci': { type: 'search', name: 'Google' }, - 'www.google.co.ck': { type: 'search', name: 'Google' }, - 'www.google.cl': { type: 'search', name: 'Google' }, - 'www.google.cm': { type: 'search', name: 'Google' }, - 'www.google.cn': { type: 'search', name: 'Google' }, - 'www.google.com.co': { type: 'search', name: 'Google' }, - 'www.google.co.cr': { type: 'search', name: 'Google' }, - 'www.google.com.cu': { type: 'search', name: 'Google' }, - 'www.google.cv': { type: 'search', name: 'Google' }, - 'www.google.com.cy': { type: 'search', name: 'Google' }, - 'www.google.cz': { type: 'search', name: 'Google' }, - 'www.google.de': { type: 'search', name: 'Google' }, - 'www.google.dj': { type: 'search', name: 'Google' }, - 'www.google.dk': { type: 'search', name: 'Google' }, - 'www.google.dm': { type: 'search', name: 'Google' }, - 'www.google.com.do': { type: 'search', name: 'Google' }, - 'www.google.dz': { type: 'search', name: 'Google' }, - 'www.google.com.ec': { type: 'search', name: 'Google' }, - 'www.google.ee': { type: 'search', name: 'Google' }, - 'www.google.com.eg': { type: 'search', name: 'Google' }, - 'www.google.es': { type: 'search', name: 'Google' }, - 'www.google.com.et': { type: 'search', name: 'Google' }, - 'www.google.fi': { type: 'search', name: 'Google' }, - 'www.google.com.fj': { type: 'search', name: 'Google' }, - 'www.google.fm': { type: 'search', name: 'Google' }, - 'www.google.fr': { type: 'search', name: 'Google' }, - 'www.google.ga': { type: 'search', name: 'Google' }, - 'www.google.gd': { type: 'search', name: 'Google' }, - 'www.google.ge': { type: 'search', name: 'Google' }, - 'www.google.gf': { type: 'search', name: 'Google' }, - 'www.google.gg': { type: 'search', name: 'Google' }, - 'www.google.com.gh': { type: 'search', name: 'Google' }, - 'www.google.com.gi': { type: 'search', name: 'Google' }, - 'www.google.gl': { type: 'search', name: 'Google' }, - 'www.google.gm': { type: 'search', name: 'Google' }, - 'www.google.gp': { type: 'search', name: 'Google' }, - 'www.google.gr': { type: 'search', name: 'Google' }, - 'www.google.com.gt': { type: 'search', name: 'Google' }, - 'www.google.gy': { type: 'search', name: 'Google' }, - 'www.google.com.hk': { type: 'search', name: 'Google' }, - 'www.google.hn': { type: 'search', name: 'Google' }, - 'www.google.hr': { type: 'search', name: 'Google' }, - 'www.google.ht': { type: 'search', name: 'Google' }, - 'www.google.hu': { type: 'search', name: 'Google' }, - 'www.google.co.id': { type: 'search', name: 'Google' }, - 'www.google.iq': { type: 'search', name: 'Google' }, - 'www.google.ie': { type: 'search', name: 'Google' }, - 'www.google.co.il': { type: 'search', name: 'Google' }, - 'www.google.im': { type: 'search', name: 'Google' }, - 'www.google.co.in': { type: 'search', name: 'Google' }, - 'www.google.io': { type: 'search', name: 'Google' }, - 'www.google.is': { type: 'search', name: 'Google' }, - 'www.google.it': { type: 'search', name: 'Google' }, - 'www.google.je': { type: 'search', name: 'Google' }, - 'www.google.com.jm': { type: 'search', name: 'Google' }, - 'www.google.jo': { type: 'search', name: 'Google' }, - 'www.google.co.jp': { type: 'search', name: 'Google' }, - 'www.google.co.ke': { type: 'search', name: 'Google' }, - 'www.google.ki': { type: 'search', name: 'Google' }, - 'www.google.kg': { type: 'search', name: 'Google' }, - 'www.google.co.kr': { type: 'search', name: 'Google' }, - 'www.google.com.kw': { type: 'search', name: 'Google' }, - 'www.google.kz': { type: 'search', name: 'Google' }, - 'www.google.la': { type: 'search', name: 'Google' }, - 'www.google.com.lb': { type: 'search', name: 'Google' }, - 'www.google.com.lc': { type: 'search', name: 'Google' }, - 'www.google.li': { type: 'search', name: 'Google' }, - 'www.google.lk': { type: 'search', name: 'Google' }, - 'www.google.co.ls': { type: 'search', name: 'Google' }, - 'www.google.lt': { type: 'search', name: 'Google' }, - 'www.google.lu': { type: 'search', name: 'Google' }, - 'www.google.lv': { type: 'search', name: 'Google' }, - 'www.google.com.ly': { type: 'search', name: 'Google' }, - 'www.google.co.ma': { type: 'search', name: 'Google' }, - 'www.google.md': { type: 'search', name: 'Google' }, - 'www.google.me': { type: 'search', name: 'Google' }, - 'www.google.mg': { type: 'search', name: 'Google' }, - 'www.google.mk': { type: 'search', name: 'Google' }, - 'www.google.ml': { type: 'search', name: 'Google' }, - 'www.google.mn': { type: 'search', name: 'Google' }, - 'www.google.ms': { type: 'search', name: 'Google' }, - 'www.google.com.mt': { type: 'search', name: 'Google' }, - 'www.google.mu': { type: 'search', name: 'Google' }, - 'www.google.mv': { type: 'search', name: 'Google' }, - 'www.google.mw': { type: 'search', name: 'Google' }, - 'www.google.com.mx': { type: 'search', name: 'Google' }, - 'www.google.com.my': { type: 'search', name: 'Google' }, - 'www.google.co.mz': { type: 'search', name: 'Google' }, - 'www.google.com.na': { type: 'search', name: 'Google' }, - 'www.google.ne': { type: 'search', name: 'Google' }, - 'www.google.com.nf': { type: 'search', name: 'Google' }, - 'www.google.com.ng': { type: 'search', name: 'Google' }, - 'www.google.com.ni': { type: 'search', name: 'Google' }, - 'www.google.nl': { type: 'search', name: 'Google' }, - 'www.google.no': { type: 'search', name: 'Google' }, - 'www.google.com.np': { type: 'search', name: 'Google' }, - 'www.google.nr': { type: 'search', name: 'Google' }, - 'www.google.nu': { type: 'search', name: 'Google' }, - 'www.google.co.nz': { type: 'search', name: 'Google' }, - 'www.google.com.om': { type: 'search', name: 'Google' }, - 'www.google.com.pa': { type: 'search', name: 'Google' }, - 'www.google.com.pe': { type: 'search', name: 'Google' }, - 'www.google.com.ph': { type: 'search', name: 'Google' }, - 'www.google.com.pk': { type: 'search', name: 'Google' }, - 'www.google.pl': { type: 'search', name: 'Google' }, - 'www.google.pn': { type: 'search', name: 'Google' }, - 'www.google.com.pr': { type: 'search', name: 'Google' }, - 'www.google.ps': { type: 'search', name: 'Google' }, - 'www.google.pt': { type: 'search', name: 'Google' }, - 'www.google.com.py': { type: 'search', name: 'Google' }, - 'www.google.com.qa': { type: 'search', name: 'Google' }, - 'www.google.ro': { type: 'search', name: 'Google' }, - 'www.google.rs': { type: 'search', name: 'Google' }, - 'www.google.ru': { type: 'search', name: 'Google' }, - 'www.google.rw': { type: 'search', name: 'Google' }, - 'www.google.com.sa': { type: 'search', name: 'Google' }, - 'www.google.com.sb': { type: 'search', name: 'Google' }, - 'www.google.sc': { type: 'search', name: 'Google' }, - 'www.google.se': { type: 'search', name: 'Google' }, - 'www.google.com.sg': { type: 'search', name: 'Google' }, - 'www.google.sh': { type: 'search', name: 'Google' }, - 'www.google.si': { type: 'search', name: 'Google' }, - 'www.google.sk': { type: 'search', name: 'Google' }, - 'www.google.com.sl': { type: 'search', name: 'Google' }, - 'www.google.sn': { type: 'search', name: 'Google' }, - 'www.google.sm': { type: 'search', name: 'Google' }, - 'www.google.so': { type: 'search', name: 'Google' }, - 'www.google.st': { type: 'search', name: 'Google' }, - 'www.google.com.sv': { type: 'search', name: 'Google' }, - 'www.google.td': { type: 'search', name: 'Google' }, - 'www.google.tg': { type: 'search', name: 'Google' }, - 'www.google.co.th': { type: 'search', name: 'Google' }, - 'www.google.com.tj': { type: 'search', name: 'Google' }, - 'www.google.tk': { type: 'search', name: 'Google' }, - 'www.google.tl': { type: 'search', name: 'Google' }, - 'www.google.tm': { type: 'search', name: 'Google' }, - 'www.google.to': { type: 'search', name: 'Google' }, - 'www.google.com.tn': { type: 'search', name: 'Google' }, - 'www.google.tn': { type: 'search', name: 'Google' }, - 'www.google.com.tr': { type: 'search', name: 'Google' }, - 'www.google.tt': { type: 'search', name: 'Google' }, - 'www.google.com.tw': { type: 'search', name: 'Google' }, - 'www.google.co.tz': { type: 'search', name: 'Google' }, - 'www.google.com.ua': { type: 'search', name: 'Google' }, - 'www.google.co.ug': { type: 'search', name: 'Google' }, - 'www.google.ae': { type: 'search', name: 'Google' }, - 'www.google.co.uk': { type: 'search', name: 'Google' }, - 'www.google.us': { type: 'search', name: 'Google' }, - 'www.google.com.uy': { type: 'search', name: 'Google' }, - 'www.google.co.uz': { type: 'search', name: 'Google' }, - 'www.google.com.vc': { type: 'search', name: 'Google' }, - 'www.google.co.ve': { type: 'search', name: 'Google' }, - 'www.google.vg': { type: 'search', name: 'Google' }, - 'www.google.co.vi': { type: 'search', name: 'Google' }, - 'www.google.com.vn': { type: 'search', name: 'Google' }, - 'www.google.vu': { type: 'search', name: 'Google' }, - 'www.google.ws': { type: 'search', name: 'Google' }, - 'www.google.co.za': { type: 'search', name: 'Google' }, - 'www.google.co.zm': { type: 'search', name: 'Google' }, - 'www.google.co.zw': { type: 'search', name: 'Google' }, - 'google.com': { type: 'search', name: 'Google' }, - 'google.ac': { type: 'search', name: 'Google' }, - 'google.ad': { type: 'search', name: 'Google' }, - 'google.com.af': { type: 'search', name: 'Google' }, - 'google.com.ag': { type: 'search', name: 'Google' }, - 'google.com.ai': { type: 'search', name: 'Google' }, - 'google.am': { type: 'search', name: 'Google' }, - 'google.it.ao': { type: 'search', name: 'Google' }, - 'google.com.ar': { type: 'search', name: 'Google' }, - 'google.as': { type: 'search', name: 'Google' }, - 'google.at': { type: 'search', name: 'Google' }, - 'google.com.au': { type: 'search', name: 'Google' }, - 'google.az': { type: 'search', name: 'Google' }, - 'google.ba': { type: 'search', name: 'Google' }, - 'google.com.bd': { type: 'search', name: 'Google' }, - 'google.be': { type: 'search', name: 'Google' }, - 'google.bf': { type: 'search', name: 'Google' }, - 'google.bg': { type: 'search', name: 'Google' }, - 'google.com.bh': { type: 'search', name: 'Google' }, - 'google.bi': { type: 'search', name: 'Google' }, - 'google.bj': { type: 'search', name: 'Google' }, - 'google.com.bn': { type: 'search', name: 'Google' }, - 'google.com.bo': { type: 'search', name: 'Google' }, - 'google.com.br': { type: 'search', name: 'Google' }, - 'google.bs': { type: 'search', name: 'Google' }, - 'google.co.bw': { type: 'search', name: 'Google' }, - 'google.com.by': { type: 'search', name: 'Google' }, - 'google.by': { type: 'search', name: 'Google' }, - 'google.com.bz': { type: 'search', name: 'Google' }, - 'google.ca': { type: 'search', name: 'Google' }, - 'google.com.kh': { type: 'search', name: 'Google' }, - 'google.cc': { type: 'search', name: 'Google' }, - 'google.cd': { type: 'search', name: 'Google' }, - 'google.cf': { type: 'search', name: 'Google' }, - 'google.cat': { type: 'search', name: 'Google' }, - 'google.cg': { type: 'search', name: 'Google' }, - 'google.ch': { type: 'search', name: 'Google' }, - 'google.ci': { type: 'search', name: 'Google' }, - 'google.co.ck': { type: 'search', name: 'Google' }, - 'google.cl': { type: 'search', name: 'Google' }, - 'google.cm': { type: 'search', name: 'Google' }, - 'google.cn': { type: 'search', name: 'Google' }, - 'google.com.co': { type: 'search', name: 'Google' }, - 'google.co.cr': { type: 'search', name: 'Google' }, - 'google.com.cu': { type: 'search', name: 'Google' }, - 'google.cv': { type: 'search', name: 'Google' }, - 'google.com.cy': { type: 'search', name: 'Google' }, - 'google.cz': { type: 'search', name: 'Google' }, - 'google.de': { type: 'search', name: 'Google' }, - 'google.dj': { type: 'search', name: 'Google' }, - 'google.dk': { type: 'search', name: 'Google' }, - 'google.dm': { type: 'search', name: 'Google' }, - 'google.com.do': { type: 'search', name: 'Google' }, - 'google.dz': { type: 'search', name: 'Google' }, - 'google.com.ec': { type: 'search', name: 'Google' }, - 'google.ee': { type: 'search', name: 'Google' }, - 'google.com.eg': { type: 'search', name: 'Google' }, - 'google.es': { type: 'search', name: 'Google' }, - 'google.com.et': { type: 'search', name: 'Google' }, - 'google.fi': { type: 'search', name: 'Google' }, - 'google.com.fj': { type: 'search', name: 'Google' }, - 'google.fm': { type: 'search', name: 'Google' }, - 'google.fr': { type: 'search', name: 'Google' }, - 'google.ga': { type: 'search', name: 'Google' }, - 'google.gd': { type: 'search', name: 'Google' }, - 'google.ge': { type: 'search', name: 'Google' }, - 'google.gf': { type: 'search', name: 'Google' }, - 'google.gg': { type: 'search', name: 'Google' }, - 'google.com.gh': { type: 'search', name: 'Google' }, - 'google.com.gi': { type: 'search', name: 'Google' }, - 'google.gl': { type: 'search', name: 'Google' }, - 'google.gm': { type: 'search', name: 'Google' }, - 'google.gp': { type: 'search', name: 'Google' }, - 'google.gr': { type: 'search', name: 'Google' }, - 'google.com.gt': { type: 'search', name: 'Google' }, - 'google.gy': { type: 'search', name: 'Google' }, - 'google.com.hk': { type: 'search', name: 'Google' }, - 'google.hn': { type: 'search', name: 'Google' }, - 'google.hr': { type: 'search', name: 'Google' }, - 'google.ht': { type: 'search', name: 'Google' }, - 'google.hu': { type: 'search', name: 'Google' }, - 'google.co.id': { type: 'search', name: 'Google' }, - 'google.iq': { type: 'search', name: 'Google' }, - 'google.ie': { type: 'search', name: 'Google' }, - 'google.co.il': { type: 'search', name: 'Google' }, - 'google.im': { type: 'search', name: 'Google' }, - 'google.co.in': { type: 'search', name: 'Google' }, - 'google.io': { type: 'search', name: 'Google' }, - 'google.is': { type: 'search', name: 'Google' }, - 'google.it': { type: 'search', name: 'Google' }, - 'google.je': { type: 'search', name: 'Google' }, - 'google.com.jm': { type: 'search', name: 'Google' }, - 'google.jo': { type: 'search', name: 'Google' }, - 'google.co.jp': { type: 'search', name: 'Google' }, - 'google.co.ke': { type: 'search', name: 'Google' }, - 'google.ki': { type: 'search', name: 'Google' }, - 'google.kg': { type: 'search', name: 'Google' }, - 'google.co.kr': { type: 'search', name: 'Google' }, - 'google.com.kw': { type: 'search', name: 'Google' }, - 'google.kz': { type: 'search', name: 'Google' }, - 'google.la': { type: 'search', name: 'Google' }, - 'google.com.lb': { type: 'search', name: 'Google' }, - 'google.com.lc': { type: 'search', name: 'Google' }, - 'google.li': { type: 'search', name: 'Google' }, - 'google.lk': { type: 'search', name: 'Google' }, - 'google.co.ls': { type: 'search', name: 'Google' }, - 'google.lt': { type: 'search', name: 'Google' }, - 'google.lu': { type: 'search', name: 'Google' }, - 'google.lv': { type: 'search', name: 'Google' }, - 'google.com.ly': { type: 'search', name: 'Google' }, - 'google.co.ma': { type: 'search', name: 'Google' }, - 'google.md': { type: 'search', name: 'Google' }, - 'google.me': { type: 'search', name: 'Google' }, - 'google.mg': { type: 'search', name: 'Google' }, - 'google.mk': { type: 'search', name: 'Google' }, - 'google.ml': { type: 'search', name: 'Google' }, - 'google.mn': { type: 'search', name: 'Google' }, - 'google.ms': { type: 'search', name: 'Google' }, - 'google.com.mt': { type: 'search', name: 'Google' }, - 'google.mu': { type: 'search', name: 'Google' }, - 'google.mv': { type: 'search', name: 'Google' }, - 'google.mw': { type: 'search', name: 'Google' }, - 'google.com.mx': { type: 'search', name: 'Google' }, - 'google.com.my': { type: 'search', name: 'Google' }, - 'google.co.mz': { type: 'search', name: 'Google' }, - 'google.com.na': { type: 'search', name: 'Google' }, - 'google.ne': { type: 'search', name: 'Google' }, - 'google.com.nf': { type: 'search', name: 'Google' }, - 'google.com.ng': { type: 'search', name: 'Google' }, - 'google.com.ni': { type: 'search', name: 'Google' }, - 'google.nl': { type: 'search', name: 'Google' }, - 'google.no': { type: 'search', name: 'Google' }, - 'google.com.np': { type: 'search', name: 'Google' }, - 'google.nr': { type: 'search', name: 'Google' }, - 'google.nu': { type: 'search', name: 'Google' }, - 'google.co.nz': { type: 'search', name: 'Google' }, - 'google.com.om': { type: 'search', name: 'Google' }, - 'google.com.pa': { type: 'search', name: 'Google' }, - 'google.com.pe': { type: 'search', name: 'Google' }, - 'google.com.ph': { type: 'search', name: 'Google' }, - 'google.com.pk': { type: 'search', name: 'Google' }, - 'google.pl': { type: 'search', name: 'Google' }, - 'google.pn': { type: 'search', name: 'Google' }, - 'google.com.pr': { type: 'search', name: 'Google' }, - 'google.ps': { type: 'search', name: 'Google' }, - 'google.pt': { type: 'search', name: 'Google' }, - 'google.com.py': { type: 'search', name: 'Google' }, - 'google.com.qa': { type: 'search', name: 'Google' }, - 'google.ro': { type: 'search', name: 'Google' }, - 'google.rs': { type: 'search', name: 'Google' }, - 'google.ru': { type: 'search', name: 'Google' }, - 'google.rw': { type: 'search', name: 'Google' }, - 'google.com.sa': { type: 'search', name: 'Google' }, - 'google.com.sb': { type: 'search', name: 'Google' }, - 'google.sc': { type: 'search', name: 'Google' }, - 'google.se': { type: 'search', name: 'Google' }, - 'google.com.sg': { type: 'search', name: 'Google' }, - 'google.sh': { type: 'search', name: 'Google' }, - 'google.si': { type: 'search', name: 'Google' }, - 'google.sk': { type: 'search', name: 'Google' }, - 'google.com.sl': { type: 'search', name: 'Google' }, - 'google.sn': { type: 'search', name: 'Google' }, - 'google.sm': { type: 'search', name: 'Google' }, - 'google.so': { type: 'search', name: 'Google' }, - 'google.st': { type: 'search', name: 'Google' }, - 'google.com.sv': { type: 'search', name: 'Google' }, - 'google.td': { type: 'search', name: 'Google' }, - 'google.tg': { type: 'search', name: 'Google' }, - 'google.co.th': { type: 'search', name: 'Google' }, - 'google.com.tj': { type: 'search', name: 'Google' }, - 'google.tk': { type: 'search', name: 'Google' }, - 'google.tl': { type: 'search', name: 'Google' }, - 'google.tm': { type: 'search', name: 'Google' }, - 'google.to': { type: 'search', name: 'Google' }, - 'google.com.tn': { type: 'search', name: 'Google' }, - 'google.com.tr': { type: 'search', name: 'Google' }, - 'google.tt': { type: 'search', name: 'Google' }, - 'google.com.tw': { type: 'search', name: 'Google' }, - 'google.co.tz': { type: 'search', name: 'Google' }, - 'google.com.ua': { type: 'search', name: 'Google' }, - 'google.co.ug': { type: 'search', name: 'Google' }, - 'google.ae': { type: 'search', name: 'Google' }, - 'google.co.uk': { type: 'search', name: 'Google' }, - 'google.us': { type: 'search', name: 'Google' }, - 'google.com.uy': { type: 'search', name: 'Google' }, - 'google.co.uz': { type: 'search', name: 'Google' }, - 'google.com.vc': { type: 'search', name: 'Google' }, - 'google.co.ve': { type: 'search', name: 'Google' }, - 'google.vg': { type: 'search', name: 'Google' }, - 'google.co.vi': { type: 'search', name: 'Google' }, - 'google.com.vn': { type: 'search', name: 'Google' }, - 'google.vu': { type: 'search', name: 'Google' }, - 'google.ws': { type: 'search', name: 'Google' }, - 'google.co.za': { type: 'search', name: 'Google' }, - 'google.co.zm': { type: 'search', name: 'Google' }, - 'google.co.zw': { type: 'search', name: 'Google' }, - 'google.tn': { type: 'search', name: 'Google' }, - 'search.avg.com': { type: 'search', name: 'Google' }, - 'isearch.avg.com': { type: 'search', name: 'Google' }, - 'www.cnn.com': { type: 'search', name: 'Google' }, - 'darkoogle.com': { type: 'search', name: 'Google' }, - 'search.darkoogle.com': { type: 'search', name: 'Google' }, - 'search.foxtab.com': { type: 'search', name: 'Google' }, - 'www.gooofullsearch.com': { type: 'search', name: 'Google' }, - 'search.hiyo.com': { type: 'search', name: 'Google' }, - 'search.incredimail.com': { type: 'search', name: 'Google' }, - 'search1.incredimail.com': { type: 'search', name: 'Google' }, - 'search2.incredimail.com': { type: 'search', name: 'Google' }, - 'search3.incredimail.com': { type: 'search', name: 'Google' }, - 'search4.incredimail.com': { type: 'search', name: 'Google' }, - 'search.incredibar.com': { type: 'search', name: 'Google' }, - 'search.sweetim.com': { type: 'search', name: 'Google' }, - 'www.fastweb.it': { type: 'search', name: 'Google' }, - 'search.juno.com': { type: 'search', name: 'Google' }, - 'find.tdc.dk': { type: 'search', name: 'Google' }, - 'searchresults.verizon.com': { type: 'search', name: 'Google' }, - 'search.walla.co.il': { type: 'search', name: 'Google' }, - 'search.alot.com': { type: 'search', name: 'Google' }, - 'www.googleearth.de': { type: 'search', name: 'Google' }, - 'www.googleearth.fr': { type: 'search', name: 'Google' }, - 'webcache.googleusercontent.com': { type: 'search', name: 'Google' }, - 'encrypted.google.com': { type: 'search', name: 'Google' }, - 'googlesyndicatedsearch.com': { type: 'search', name: 'Google' }, - 'com.google.android.googlequicksearchbox': { type: 'search', name: 'Google' }, - 'www.blogpulse.com': { type: 'search', name: 'Blogpulse' }, - 'www.hooseek.com': { type: 'search', name: 'Hooseek.com' }, - 'www.dalesearch.com': { type: 'search', name: 'Dalesearch' }, - 'rechercher.aliceadsl.fr': { type: 'search', name: 'Alice Adsl' }, - 'suche.t-online.de': { type: 'search', name: 'T-Online' }, - 'brisbane.t-online.de': { type: 'search', name: 'T-Online' }, - 'navigationshilfe.t-online.de': { type: 'search', name: 'T-Online' }, - 'www.sougou.com': { type: 'search', name: 'Sogou' }, - 'www.soso.com': { type: 'search', name: 'Sogou' }, - 'req.-hit-parade.com': { type: 'search', name: 'Hit-Parade' }, - 'class.hit-parade.com': { type: 'search', name: 'Hit-Parade' }, - 'www.hit-parade.com': { type: 'search', name: 'Hit-Parade' }, - 'www.searchcanvas.com': { type: 'search', name: 'SearchCanvas' }, - 'junglekey.com': { type: 'search', name: 'Jungle Key' }, - 'junglekey.fr': { type: 'search', name: 'Jungle Key' }, - 'www.google.interia.pl': { type: 'search', name: 'Interia' }, - 'search.genieo.com': { type: 'search', name: 'Genieo' }, - 'search.tiscali.it': { type: 'search', name: 'Tiscali' }, - 'search-dyn.tiscali.it': { type: 'search', name: 'Tiscali' }, - 'hledani.tiscali.cz': { type: 'search', name: 'Tiscali' }, - 'www.gomeo.com': { type: 'search', name: 'Gomeo' }, - 'webmail.bigpond.com': { type: 'email', name: 'Bigpond' }, - 'webmail2.bigpond.com': { type: 'email', name: 'Bigpond' }, - 'email.telstra.com': { type: 'email', name: 'Bigpond' }, - 'basic.messaging.bigpond.com': { type: 'email', name: 'Bigpond' }, - 'mail.naver.com': { type: 'email', name: 'Naver Mail' }, - 'mail.zoho.com': { type: 'email', name: 'Zoho' }, - 'webmail.virginbroadband.com.au': { type: 'email', name: 'Virgin' }, - 'mail.yahoo.net': { type: 'email', name: 'Yahoo! Mail' }, - 'mail.yahoo.com': { type: 'email', name: 'Yahoo! Mail' }, - 'mail.yahoo.co.uk': { type: 'email', name: 'Yahoo! Mail' }, - 'mail.yahoo.co.jp': { type: 'email', name: 'Yahoo! Mail' }, - 'com.yahoo.mobile.client.android.mail': { - type: 'email', - name: 'Yahoo! Mail', - }, - 'webmail.iinet.net.au': { type: 'email', name: 'iiNet' }, - 'mail.iinet.net.au': { type: 'email', name: 'iiNet' }, - 'mail.e1.ru': { type: 'email', name: 'E1.ru' }, - 'webmail.vodafone.co.nz': { type: 'email', name: 'Vodafone' }, - 'mail.126.com': { type: 'email', name: '126 Mail' }, - 'com.mailchimp.mailchimp': { type: 'email', name: 'Mailchimp' }, - 'inbox.com': { type: 'email', name: 'Inbox.com' }, - 'webmail.iprimus.com.au': { type: 'email', name: 'iPrimus' }, - 'mail.qq.com': { type: 'email', name: 'QQ Mail' }, - 'exmail.qq.com': { type: 'email', name: 'QQ Mail' }, - 'mail.qip.ru': { type: 'email', name: 'QIP' }, - 'sibmail.com': { type: 'email', name: 'Sibmail' }, - 'webmail.freenet.de': { type: 'email', name: 'Freenet' }, - 'email.seznam.cz': { type: 'email', name: 'Seznam Mail' }, - 'webmail.westnet.com.au': { type: 'email', name: 'Westnet' }, - 'mail.live.com': { type: 'email', name: 'Outlook.com' }, - 'outlook.live.com': { type: 'email', name: 'Outlook.com' }, - 'com.microsoft.office.outlook': { type: 'email', name: 'Outlook.com' }, - 'webmail.dodo.com.au': { type: 'email', name: 'Dodo' }, - 'webmail.2degreesbroadband.co.nz': { type: 'email', name: '2degrees' }, - 'mail2.daum.net': { type: 'email', name: 'Daum Mail' }, - 'mail.daum.net': { type: 'email', name: 'Daum Mail' }, - 'post.ru': { type: 'email', name: 'Beeline' }, - 'e.mail.ru': { type: 'email', name: 'Mail.ru' }, - 'touch.mail.ru': { type: 'email', name: 'Mail.ru' }, - 'webmail.adam.com.au': { type: 'email', name: 'Adam Internet' }, - 'orange.fr/webmail': { type: 'email', name: 'Orange Webmail' }, - 'com.earthlink.myearthlink': { type: 'email', name: 'earthlink' }, - 'mail.aol.com': { type: 'email', name: 'AOL Mail' }, - 'com.aol.mobile.aolapp': { type: 'email', name: 'AOL Mail' }, - 'webmail.netspace.net.au': { type: 'email', name: 'Netspace' }, - 'webmail.optuszoo.com.au': { type: 'email', name: 'Optus Zoo' }, - 'webmail.optusnet.com.au': { type: 'email', name: 'Optus Zoo' }, - 'webmail.commander.net.au': { type: 'email', name: 'Commander' }, - 'mastermail.ru': { type: 'email', name: 'Mastermail' }, - 'm.mastermail.ru': { type: 'email', name: 'Mastermail' }, - 'mail.yandex.ru': { type: 'email', name: 'Yandex' }, - 'mail.yandex.com': { type: 'email', name: 'Yandex' }, - 'mail.yandex.kz': { type: 'email', name: 'Yandex' }, - 'mail.yandex.ua': { type: 'email', name: 'Yandex' }, - 'mail.yandex.by': { type: 'email', name: 'Yandex' }, - 'mail.163.com': { type: 'email', name: '163 Mail' }, - 'mail.ukr.net': { type: 'email', name: 'Ukr.net' }, - 'mail.rambler.ru': { type: 'email', name: 'Rambler' }, - 'mail.mynet.com': { type: 'email', name: 'Mynet Mail' }, - 'mail.google.com': { type: 'email', name: 'Gmail' }, - 'com.google.android.gm': { type: 'email', name: 'Gmail' }, - 'inbox.google.com': { type: 'email', name: 'Gmail' }, - 'adspirit.de': { type: 'paid', name: 'AdSpirit' }, - 'rtbcity.com': { type: 'paid', name: 'AdSpirit' }, - 'plusperformance.com': { type: 'paid', name: 'AdSpirit' }, - 'flashtalking.com': { type: 'paid', name: 'Flashtalking' }, - 'servedby.flashtalking.com': { type: 'paid', name: 'Flashtalking' }, - 'wunderloop.net': { type: 'paid', name: 'AudienceScience' }, - 'paid.outbrain.com': { type: 'paid', name: 'Outbrain' }, - 'yieldmo.com': { type: 'paid', name: 'Yieldmo' }, - 'mozo.com.au': { type: 'paid', name: 'Mozo' }, - 'a.mozo.com.au': { type: 'paid', name: 'Mozo' }, - 'acuityplatform.com': { type: 'paid', name: 'Acuity Ads' }, - 'lfstmedia.com': { type: 'paid', name: 'LifeStreet' }, - 'microad.jp': { type: 'paid', name: 'MicroAd' }, - 'trc.taboola.com': { type: 'paid', name: 'Taboola' }, - 'api.taboola.com': { type: 'paid', name: 'Taboola' }, - 'taboola.com': { type: 'paid', name: 'Taboola' }, - 'ad.doubleclick.net': { type: 'paid', name: 'Doubleclick' }, - 'ad-apac.doubleclick.net': { type: 'paid', name: 'Doubleclick' }, - 's0.2mdn.net': { type: 'paid', name: 'Doubleclick' }, - 's1.2mdn.net': { type: 'paid', name: 'Doubleclick' }, - 'dp.g.doubleclick.net': { type: 'paid', name: 'Doubleclick' }, - 'pubads.g.doubleclick.net': { type: 'paid', name: 'Doubleclick' }, - 'adform.net': { type: 'paid', name: 'Adform' }, - 'bs.serving-sys.com': { type: 'paid', name: 'Sizmek' }, - 'cas.jp.as.criteo.com': { type: 'paid', name: 'Criteo' }, - 'cas.criteo.com': { type: 'paid', name: 'Criteo' }, - 'adingo.jp': { type: 'paid', name: 'Fluct' }, - 'lowermybills.com': { type: 'paid', name: 'LowerMyBills' }, - 'www.whitepages.com.au': { type: 'paid', name: 'White Pages' }, - 'mobile.whitepages.com.au': { type: 'paid', name: 'White Pages' }, - 'adadvisor.net': { type: 'paid', name: 'Neustar AdAdvisor' }, - 'nexage.com': { type: 'paid', name: 'ONE by AOL' }, - 'mixpo.com': { type: 'paid', name: 'Mixpo' }, - 'optimized-by.rubiconproject.com': { type: 'paid', name: 'Rubicon Project' }, - 'sshowads.pubmatic.com': { type: 'paid', name: 'PubMatic' }, - 'jivox.com': { type: 'paid', name: 'Jivox' }, - 'bidswitch.net': { type: 'paid', name: 'BidSwitch' }, - 'sonobi.com': { type: 'paid', name: 'Sonobi' }, - 'steelhousemedia.com': { type: 'paid', name: 'SteelHouse' }, - 'adroll.com': { type: 'paid', name: 'AdRoll' }, - 'adnet.de': { type: 'paid', name: 'AdNET' }, - 'cdnx.tribalfusion.com': { type: 'paid', name: 'Tribal Fusion' }, - 'market.yandex.ru': { type: 'paid', name: 'Yandex.Market' }, - 'm.market.yandex.ru': { type: 'paid', name: 'Yandex.Market' }, - 'stickyadstv.com': { type: 'paid', name: 'StickyADS.tv' }, - 'sfx.stickyadstv.com': { type: 'paid', name: 'StickyADS.tv' }, - 'zedo.com': { type: 'paid', name: 'ZEDO' }, - 'z1.zedo.com': { type: 'paid', name: 'ZEDO' }, - 'farm.plista.com': { type: 'paid', name: 'Plista' }, - 'ib.adnxs.com': { type: 'paid', name: 'AppNexus' }, - 'adnxs.com': { type: 'paid', name: 'AppNexus' }, - '247realmedia.com': { type: 'paid', name: 'AppNexus' }, - 'lijit.com': { type: 'paid', name: 'Sovrn' }, - 'www.googleadservices.com': { type: 'paid', name: 'Google' }, - 'partner.googleadservices.com': { type: 'paid', name: 'Google' }, - 'googleads.g.doubleclick.net': { type: 'paid', name: 'Google' }, - 'tpc.googlesyndication.com': { type: 'paid', name: 'Google' }, - 'googleadservices.com': { type: 'paid', name: 'Google' }, - 'imasdk.googleapis.com': { type: 'paid', name: 'Google' }, - 'eyeota.net': { type: 'paid', name: 'Eyeota' }, - 'price.ru': { type: 'paid', name: 'Price.ru' }, - 'v.price.ru': { type: 'paid', name: 'Price.ru' }, - 'us-ads.openx.net': { type: 'paid', name: 'OpenX' }, - 'openx.net': { type: 'paid', name: 'OpenX' }, - 'servedbyopenx.com': { type: 'paid', name: 'OpenX' }, - 'openxenterprise.com': { type: 'paid', name: 'OpenX' }, - 'casalemedia.com': { type: 'paid', name: 'Casale Media' }, - 'adition.com': { type: 'paid', name: 'Adition' }, - 'an.yandex.ru': { type: 'paid', name: 'Yandex.Direct' }, - 'yabs.yandex.ru': { type: 'paid', name: 'Yandex.Direct' }, - 'yabs.yandex.ua': { type: 'paid', name: 'Yandex.Direct' }, - 'yabs.yandex.com': { type: 'paid', name: 'Yandex.Direct' }, - 'yabs.yandex.by': { type: 'paid', name: 'Yandex.Direct' }, - 'adfox.ru': { type: 'paid', name: 'ADFOX' }, - 'www.adfox.ru': { type: 'paid', name: 'ADFOX' }, - 'ads.adfox.ru': { type: 'paid', name: 'ADFOX' }, - 'www.ads.adfox.ru': { type: 'paid', name: 'ADFOX' }, - 'torg.mail.ru': { type: 'paid', name: 'Torg.Mail.ru' }, - 'sociomantic.com': { type: 'paid', name: 'Sociomantic Labs' }, - 'hi5.com': { type: 'social', name: 'hi5' }, - 'friendster.com': { type: 'social', name: 'Friendster' }, - 'vkrugudruzei.ru': { type: 'social', name: 'vKruguDruzei.ru' }, - 'xanga.com': { type: 'social', name: 'Xanga' }, - 'myspace.com': { type: 'social', name: 'Myspace' }, - 'buzznet.com': { type: 'social', name: 'Buzznet' }, - 'mylife.ru': { type: 'social', name: 'MyLife' }, - 'flickr.com': { type: 'social', name: 'Flickr' }, - 'forums.whirlpool.net.au': { type: 'social', name: 'Whirlpool' }, - 'sonico.com': { type: 'social', name: 'Sonico.com' }, - 'odnoklassniki.ru': { type: 'social', name: 'Odnoklassniki' }, - 'ok.ru': { type: 'social', name: 'Odnoklassniki' }, - 'tildes.net': { type: 'social', name: 'Tildes' }, - 'com.talklittle.android.tildes': { type: 'social', name: 'Tildes' }, - 'classmates.com': { type: 'social', name: 'Classmates' }, - 'friendsreunited.com': { type: 'social', name: 'Friends Reunited' }, - 'news.ycombinator.com': { type: 'social', name: 'Hacker News' }, - 'io.github.hidroh.materialistic': { type: 'social', name: 'Hacker News' }, - 'quora.com': { type: 'social', name: 'Quora' }, - 'livejournal.ru': { type: 'social', name: 'LiveJournal' }, - 'netlog.com': { type: 'social', name: 'Netlog' }, - 'orkut.com': { type: 'social', name: 'Orkut' }, - 'myheritage.com': { type: 'social', name: 'MyHeritage' }, - 'multiply.com': { type: 'social', name: 'Multiply' }, - 'threads.net': { type: 'social', name: 'Threads' }, - 'l.threads.net': { type: 'social', name: 'Threads' }, - 'com.instagram.barcelona': { type: 'social', name: 'Threads' }, - 'myyearbook.com': { type: 'social', name: 'myYearbook' }, - 'renren.com': { type: 'social', name: 'Renren' }, - 'app.slack.com': { type: 'social', name: 'Slack' }, - 'com.slack': { type: 'social', name: 'Slack' }, - 'weeworld.com': { type: 'social', name: 'WeeWorld' }, - 'vimeo.com': { type: 'social', name: 'Vimeo' }, - 'Sozluk.com': { type: 'social', name: 'Eksi Sozluk' }, - 'sourtimes.org': { type: 'social', name: 'Eksi Sozluk' }, - 'mixi.jp': { type: 'social', name: 'Mixi' }, - 'geni.com': { type: 'social', name: 'Geni' }, - 'uludagsozluk.com': { type: 'social', name: 'Uludag Sozluk' }, - 'ulusozluk.com': { type: 'social', name: 'Uludag Sozluk' }, - 'sourceforge.net': { type: 'social', name: 'SourceForge' }, - 'plaxo.com': { type: 'social', name: 'Plaxo' }, - 'taringa.net': { type: 'social', name: 'Taringa!' }, - 'login.tagged.com': { type: 'social', name: 'Tagged' }, - 'xing.com': { type: 'social', name: 'XING' }, - 'instagram.com': { type: 'social', name: 'Instagram' }, - 'l.instagram.com': { type: 'social', name: 'Instagram' }, - 'com.instagram.android': { type: 'social', name: 'Instagram' }, - 'm.vk.com': { type: 'social', name: 'Vkontakte' }, - 'vk.com': { type: 'social', name: 'Vkontakte' }, - 'away.vk.com': { type: 'social', name: 'Vkontakte' }, - 'vkontakte.ru': { type: 'social', name: 'Vkontakte' }, - 'weibo.com': { type: 'social', name: 'Weibo' }, - 't.cn': { type: 'social', name: 'Weibo' }, - 'web.telegram.org': { type: 'social', name: 'Telegram' }, - 'org.telegram.messenger': { type: 'social', name: 'Telegram' }, - 'org.telegram.messenger.web': { type: 'social', name: 'Telegram' }, - 'org.aka.messenger': { type: 'social', name: 'Telegram' }, - 'org.telegram.biftogram': { type: 'social', name: 'Telegram' }, - 'org.telegram.plus': { type: 'social', name: 'Telegram' }, - 'twitter.com': { type: 'social', name: 'Twitter' }, - 't.co': { type: 'social', name: 'Twitter' }, - 'com.twitter.android': { type: 'social', name: 'Twitter' }, - 'com.snapchat.android': { type: 'social', name: 'Snapchat' }, - 'snapchat.com': { type: 'social', name: 'Snapchat' }, - 'donanimhaber.com': { type: 'social', name: 'Donanimhaber' }, - 'wayn.com': { type: 'social', name: 'WAYN' }, - 'web.skype.com': { type: 'social', name: 'Skype' }, - 'my.mail.ru': { type: 'social', name: 'Mail.ru' }, - 'badoo.com': { type: 'social', name: 'Badoo' }, - 'instela.com': { type: 'social', name: 'Instela' }, - 'habbo.com': { type: 'social', name: 'Habbo' }, - 'pinterest.ca': { type: 'social', name: 'Pinterest' }, - 'pinterest.cl': { type: 'social', name: 'Pinterest' }, - 'pinterest.co.kr': { type: 'social', name: 'Pinterest' }, - 'pinterest.com': { type: 'social', name: 'Pinterest' }, - 'pinterest.com.au': { type: 'social', name: 'Pinterest' }, - 'pinterest.co.uk': { type: 'social', name: 'Pinterest' }, - 'pinterest.de': { type: 'social', name: 'Pinterest' }, - 'pinterest.dk': { type: 'social', name: 'Pinterest' }, - 'pinterest.es': { type: 'social', name: 'Pinterest' }, - 'pinterest.fr': { type: 'social', name: 'Pinterest' }, - 'pinterest.jp': { type: 'social', name: 'Pinterest' }, - 'pinterest.nz': { type: 'social', name: 'Pinterest' }, - 'pinterest.pt': { type: 'social', name: 'Pinterest' }, - 'pinterest.se': { type: 'social', name: 'Pinterest' }, - 'pinterest.at': { type: 'social', name: 'Pinterest' }, - 'pinterest.ch': { type: 'social', name: 'Pinterest' }, - 'pinterest.com.mx': { type: 'social', name: 'Pinterest' }, - 'pinterest.ie': { type: 'social', name: 'Pinterest' }, - 'pinterest.it': { type: 'social', name: 'Pinterest' }, - 'pinterest.ph': { type: 'social', name: 'Pinterest' }, - 'pinterest.ru': { type: 'social', name: 'Pinterest' }, - 'com.pinterest': { type: 'social', name: 'Pinterest' }, - 'com.linkedin.android': { type: 'social', name: 'LinkedIn' }, - 'linkedin.com': { type: 'social', name: 'LinkedIn' }, - 'lnkd.in': { type: 'social', name: 'LinkedIn' }, - 'foursquare.com': { type: 'social', name: 'Foursquare' }, - 'douban.com': { type: 'social', name: 'Douban' }, - 'login.live.com': { type: 'social', name: 'Windows Live Spaces' }, - 'blackplanet.com': { type: 'social', name: 'BlackPlanet' }, - 'global.cyworld.com': { type: 'social', name: 'Cyworld' }, - 'getpocket.com': { type: 'social', name: 'Pocket' }, - 'skyrock.com': { type: 'social', name: 'Skyrock' }, - 'facebook.com': { type: 'social', name: 'Facebook' }, - 'fb.me': { type: 'social', name: 'Facebook' }, - 'm.facebook.com': { type: 'social', name: 'Facebook' }, - 'l.facebook.com': { type: 'social', name: 'Facebook' }, - 'lm.facebook.com': { type: 'social', name: 'Facebook' }, - 'com.facebook.katana': { type: 'social', name: 'Facebook' }, - 'web.whatsapp.com': { type: 'social', name: 'WhatsApp' }, - 'com.whatsapp': { type: 'social', name: 'WhatsApp' }, - 'redirect.disqus.com': { type: 'social', name: 'Disqus' }, - 'disq.us': { type: 'social', name: 'Disqus' }, - 'disqus.com': { type: 'social', name: 'Disqus' }, - 'studivz.net': { type: 'social', name: 'StudiVZ' }, - 'fotolog.com': { type: 'social', name: 'Fotolog' }, - 'itusozluk.com': { type: 'social', name: 'ITU Sozluk' }, - 'url.google.com': { type: 'social', name: 'Google+' }, - 'plus.google.com': { type: 'social', name: 'Google+' }, - 'nk.pl': { type: 'social', name: 'Nasza-klasa.pl' }, - 'qzone.qq.com': { type: 'social', name: 'Qzone' }, - 'flixster.com': { type: 'social', name: 'Flixster' }, - 'bebo.com': { type: 'social', name: 'Bebo' }, - 'tuenti.com': { type: 'social', name: 'Tuenti' }, - 'youtube.com': { type: 'social', name: 'Youtube' }, - 'youtu.be': { type: 'social', name: 'Youtube' }, - 'reddit.com': { type: 'social', name: 'Reddit' }, - 'io.syncapps.lemmy_sync': { type: 'social', name: 'Reddit' }, - 'com.laurencedawson.reddit_sync': { type: 'social', name: 'Reddit' }, - 'com.laurencedawson.reddit_sync.pro': { type: 'social', name: 'Reddit' }, - 'viadeo.com': { type: 'social', name: 'Viadeo' }, - 'github.com': { type: 'social', name: 'GitHub' }, - 'stackoverflow.com': { type: 'social', name: 'StackOverflow' }, - 'gaiaonline.com': { type: 'social', name: 'Gaia Online' }, - 'stumbleupon.com': { type: 'social', name: 'StumbleUpon' }, - 'inci.sozlukspot.com': { type: 'social', name: 'Inci Sozluk' }, - 'incisozluk.com': { type: 'social', name: 'Inci Sozluk' }, - 'incisozluk.cc': { type: 'social', name: 'Inci Sozluk' }, - 'identi.ca': { type: 'social', name: 'Identi.ca' }, - 'lastfm.ru': { type: 'social', name: 'Last.fm' }, - 'tumblr.com': { type: 'social', name: 'Tumblr' }, - 't.umblr.com': { type: 'social', name: 'Tumblr' }, - 'tiktok.com': { type: 'social', name: 'TikTok' }, - 'hocam.com': { type: 'social', name: 'Hocam.com' }, - 'delicious.com': { type: 'social', name: 'Delicious' }, - 'hyves.nl': { type: 'social', name: 'Hyves' }, - 'paper.li': { type: 'social', name: 'Paper.li' }, - 'moikrug.ru': { type: 'social', name: 'MoiKrug.ru' }, - 'bsky.app': { type: 'social', name: 'Bluesky' }, -} as const; -export default referrers; diff --git a/apps/api/src/referrers/referrers.readme.md b/apps/api/src/referrers/referrers.readme.md deleted file mode 100644 index 098d1c2a..00000000 --- a/apps/api/src/referrers/referrers.readme.md +++ /dev/null @@ -1,5 +0,0 @@ -# Snowplow Referer Parser - -The file index.ts in this dir is generated from snowplows referer database [Snowplow Referer Parser](https://github.com/snowplow-referer-parser/referer-parser). - -The orginal [referers.yml](https://github.com/snowplow-referer-parser/referer-parser/blob/master/resources/referers.yml) is based on Piwik's SearchEngines.php and Socials.php, copyright 2012 Matthieu Aubry and available under the GNU General Public License v3. diff --git a/apps/worker/package.json b/apps/worker/package.json index e4331990..5bc0551b 100644 --- a/apps/worker/package.json +++ b/apps/worker/package.json @@ -2,11 +2,13 @@ "name": "@openpanel/worker", "version": "0.0.3", "scripts": { + "test": "vitest", "dev": "dotenv -e ../../.env -c -v WATCH=1 tsup", "testing": "WORKER_PORT=9999 pnpm dev", "start": "node dist/index.js", "build": "rm -rf dist && tsup", - "typecheck": "tsc --noEmit" + "typecheck": "tsc --noEmit", + "gen:referrers": "jiti scripts/get-referrers.ts && biome format --write ./src/referrers/index.ts" }, "dependencies": { "@bull-board/api": "5.21.0", diff --git a/apps/worker/scripts/get-referrers.ts b/apps/worker/scripts/get-referrers.ts new file mode 100644 index 00000000..bc53c2e5 --- /dev/null +++ b/apps/worker/scripts/get-referrers.ts @@ -0,0 +1,91 @@ +import fs from 'node:fs'; +import path from 'node:path'; + +// extras +const extraReferrers = { + 'zoom.us': { type: 'social', name: 'Zoom' }, + 'apple.com': { type: 'tech', name: 'Apple' }, + 'adobe.com': { type: 'tech', name: 'Adobe' }, + 'figma.com': { type: 'tech', name: 'Figma' }, + 'wix.com': { type: 'commerce', name: 'Wix' }, + 'gmail.com': { type: 'email', name: 'Gmail' }, + 'notion.so': { type: 'tech', name: 'Notion' }, + 'ebay.com': { type: 'commerce', name: 'eBay' }, + 'github.com': { type: 'tech', name: 'GitHub' }, + 'gitlab.com': { type: 'tech', name: 'GitLab' }, + 'slack.com': { type: 'social', name: 'Slack' }, + 'etsy.com': { type: 'commerce', name: 'Etsy' }, + 'bsky.app': { type: 'social', name: 'Bluesky' }, + 'twitch.tv': { type: 'content', name: 'Twitch' }, + 'dropbox.com': { type: 'tech', name: 'Dropbox' }, + 'outlook.com': { type: 'email', name: 'Outlook' }, + 'medium.com': { type: 'content', name: 'Medium' }, + 'paypal.com': { type: 'commerce', name: 'PayPal' }, + 'discord.com': { type: 'social', name: 'Discord' }, + 'stripe.com': { type: 'commerce', name: 'Stripe' }, + 'spotify.com': { type: 'content', name: 'Spotify' }, + 'netflix.com': { type: 'content', name: 'Netflix' }, + 'whatsapp.com': { type: 'social', name: 'WhatsApp' }, + 'shopify.com': { type: 'commerce', name: 'Shopify' }, + 'microsoft.com': { type: 'tech', name: 'Microsoft' }, + 'alibaba.com': { type: 'commerce', name: 'Alibaba' }, + 'telegram.org': { type: 'social', name: 'Telegram' }, + 'substack.com': { type: 'content', name: 'Substack' }, + 'salesforce.com': { type: 'tech', name: 'Salesforce' }, + 'instagram.com': { type: 'social', name: 'Instagram' }, + 'wikipedia.org': { type: 'content', name: 'Wikipedia' }, + 'mastodon.social': { type: 'social', name: 'Mastodon' }, + 'office.com': { type: 'tech', name: 'Microsoft Office' }, + 'squarespace.com': { type: 'commerce', name: 'Squarespace' }, + 'stackoverflow.com': { type: 'tech', name: 'Stack Overflow' }, + 'teams.microsoft.com': { type: 'social', name: 'Microsoft Teams' }, +}; + +function transform(data: any) { + const obj: Record = {}; + for (const type in data) { + for (const name in data[type]) { + const domains = data[type][name].domains ?? []; + for (const domain of domains) { + obj[domain] = { + type, + name, + }; + } + } + } + + return obj; +} + +async function main() { + // Get document, or throw exception on error + try { + const data = await fetch( + 'https://s3-eu-west-1.amazonaws.com/snowplow-hosted-assets/third-party/referer-parser/referers-latest.json', + ).then((res) => res.json()); + + fs.writeFileSync( + path.resolve(__dirname, '../../worker/src/referrers/index.ts'), + [ + '// This file is generated by the script get-referrers.ts', + '', + '// The data is fetch from snowplow-referer-parser https://github.com/snowplow-referer-parser/referer-parser', + `// The orginal referers.yml is based on Piwik's SearchEngines.php and Socials.php, copyright 2012 Matthieu Aubry and available under the GNU General Public License v3.`, + '', + `const referrers: Record = ${JSON.stringify( + { + ...transform(data), + ...extraReferrers, + }, + )} as const;`, + 'export default referrers;', + ].join('\n'), + 'utf-8', + ); + } catch (e) { + console.log(e); + } +} + +main(); diff --git a/apps/worker/src/jobs/events.incoming-event.ts b/apps/worker/src/jobs/events.incoming-event.ts index adc2272f..693e4129 100644 --- a/apps/worker/src/jobs/events.incoming-event.ts +++ b/apps/worker/src/jobs/events.incoming-event.ts @@ -121,14 +121,36 @@ export async function incomingEvent( // if timestamp is from the past we dont want to create a new session if (uaInfo.isServer || isTimestampFromThePast) { - const event = profileId + const screenView = profileId ? await eventBuffer.getLastScreenView({ profileId, projectId, }) : null; - const payload = merge(omit(['properties'], event ?? {}), baseEvent); + const payload = { + ...baseEvent, + deviceId: screenView?.deviceId ?? '', + sessionId: screenView?.sessionId ?? '', + referrer: screenView?.referrer ?? undefined, + referrerName: screenView?.referrerName ?? undefined, + referrerType: screenView?.referrerType ?? undefined, + path: screenView?.path ?? baseEvent.path, + os: screenView?.os ?? baseEvent.os, + osVersion: screenView?.osVersion ?? baseEvent.osVersion, + browserVersion: screenView?.browserVersion ?? baseEvent.browserVersion, + browser: screenView?.browser ?? baseEvent.browser, + device: screenView?.device ?? baseEvent.device, + brand: screenView?.brand ?? baseEvent.brand, + model: screenView?.model ?? baseEvent.model, + city: screenView?.city ?? baseEvent.city, + country: screenView?.country ?? baseEvent.country, + region: screenView?.region ?? baseEvent.region, + longitude: screenView?.longitude ?? baseEvent.longitude, + latitude: screenView?.latitude ?? baseEvent.latitude, + origin: screenView?.origin ?? baseEvent.origin, + }; + return createEventAndNotify( payload as IServiceEvent, job.data.payload, @@ -180,7 +202,9 @@ export async function incomingEvent( const event = await createEventAndNotify(payload, job.data.payload, logger); - await createSessionEndJob({ payload }); + if (!sessionEnd) { + await createSessionEndJob({ payload }); + } return event; } diff --git a/apps/worker/src/jobs/events.incoming-events.test.ts b/apps/worker/src/jobs/events.incoming-events.test.ts index d4920fc6..292453d4 100644 --- a/apps/worker/src/jobs/events.incoming-events.test.ts +++ b/apps/worker/src/jobs/events.incoming-events.test.ts @@ -1,351 +1,380 @@ -// import { type Mock, beforeEach, describe, expect, it, mock } from 'bun:test'; -// import { getTime, toISOString } from '@openpanel/common'; -// import type { Job } from 'bullmq'; -// import { SESSION_TIMEOUT, incomingEvent } from './events.incoming-event'; +import { type IServiceEvent, createEvent } from '@openpanel/db'; +import { eventBuffer } from '@openpanel/db'; +import { sessionsQueue } from '@openpanel/queue'; +import type { Job } from 'bullmq'; +import { type Mock, beforeEach, describe, expect, it, vi } from 'vitest'; +import { incomingEvent } from './events.incoming-event'; -// const projectId = 'test-project'; -// const currentDeviceId = 'device-123'; -// const previousDeviceId = 'device-456'; -// const geo = { -// country: 'US', -// city: 'New York', -// region: 'NY', -// longitude: 0, -// latitude: 0, -// }; +vi.mock('@openpanel/queue'); +vi.mock('@openpanel/db', async () => { + const actual = await vi.importActual('@openpanel/db'); + return { + ...actual, + createEvent: vi.fn(), + getLastScreenView: vi.fn(), + checkNotificationRulesForEvent: vi.fn().mockResolvedValue(true), + eventBuffer: { + getLastScreenView: vi.fn(), + }, + }; +}); -// const createEvent = mock(() => {}); -// const getLastScreenViewFromProfileId = mock(); -// // // Mock dependencies -// mock.module('@openpanel/db', () => ({ -// createEvent, -// getLastScreenViewFromProfileId, -// })); +// 30 minutes +const SESSION_TIMEOUT = 30 * 60 * 1000; +const projectId = 'test-project'; +const currentDeviceId = 'device-123'; +const previousDeviceId = 'device-456'; +const geo = { + country: 'US', + city: 'New York', + region: 'NY', + longitude: 0, + latitude: 0, +}; -// const sessionsQueue = { add: mock(() => Promise.resolve({})) }; +describe('incomingEvent', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); -// const findJobByPrefix = mock(); + it('should create a session start and an event', async () => { + const spySessionsQueueAdd = vi.spyOn(sessionsQueue, 'add'); + const timestamp = new Date(); + // Mock job data + const jobData = { + payload: { + geo, + event: { + name: 'test_event', + timestamp: timestamp.toISOString(), + properties: { __path: 'https://example.com/test' }, + }, + headers: { + 'request-id': '123', + 'user-agent': + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', + 'openpanel-sdk-name': 'web', + 'openpanel-sdk-version': '1.0.0', + }, + projectId, + currentDeviceId, + previousDeviceId, + }, + }; -// mock.module('@openpanel/queue', () => ({ -// sessionsQueue, -// findJobByPrefix, -// })); + const job = { data: jobData } as Job; -// const getRedisQueue = mock(() => ({ -// keys: mock(() => Promise.resolve([])), -// })); + // Execute the job + await incomingEvent(job); -// mock.module('@openpanel/redis', () => ({ -// getRedisQueue, -// })); + const event = { + name: 'test_event', + deviceId: currentDeviceId, + profileId: '', + sessionId: expect.stringMatching( + /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i, + ), + projectId, + properties: { + __hash: undefined, + __query: undefined, + __user_agent: jobData.payload.headers['user-agent'], + __reqId: jobData.payload.headers['request-id'], + }, + createdAt: timestamp, + country: 'US', + city: 'New York', + region: 'NY', + longitude: 0, + latitude: 0, + os: 'Windows', + osVersion: '10', + browser: 'Chrome', + browserVersion: '91.0.4472.124', + device: 'desktop', + brand: undefined, + model: undefined, + duration: 0, + path: '/test', + origin: 'https://example.com', + referrer: '', + referrerName: '', + referrerType: 'unknown', + sdkName: jobData.payload.headers['openpanel-sdk-name'], + sdkVersion: jobData.payload.headers['openpanel-sdk-version'], + }; -// describe('incomingEvent', () => { -// beforeEach(() => { -// createEvent.mockClear(); -// findJobByPrefix.mockClear(); -// sessionsQueue.add.mockClear(); -// getLastScreenViewFromProfileId.mockClear(); -// }); + expect(spySessionsQueueAdd).toHaveBeenCalledWith( + 'session', + { + type: 'createSessionEnd', + payload: expect.objectContaining(event), + }, + { + delay: SESSION_TIMEOUT, + jobId: `sessionEnd:${projectId}:${currentDeviceId}`, + attempts: 3, + backoff: { + delay: 200, + type: 'exponential', + }, + }, + ); -// it('should create a session start and an event', async () => { -// const timestamp = new Date(); -// // Mock job data -// const jobData = { -// payload: { -// geo, -// event: { -// name: 'test_event', -// timestamp: timestamp.toISOString(), -// properties: { __path: 'https://example.com/test' }, -// }, -// headers: { -// 'user-agent': -// 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', -// 'openpanel-sdk-name': 'web', -// 'openpanel-sdk-version': '1.0.0', -// }, -// projectId, -// currentDeviceId, -// previousDeviceId, -// priority: true, -// }, -// }; + expect((createEvent as Mock).mock.calls[0]![0]).toStrictEqual({ + ...event, + createdAt: new Date(timestamp.getTime() - 100), + name: 'session_start', + }); + expect((createEvent as Mock).mock.calls[1]).toMatchObject([event]); + }); -// const job = { data: jobData } as Job; + it('should reuse existing session', async () => { + const spySessionsQueueAdd = vi.spyOn(sessionsQueue, 'add'); + const spySessionsQueueGetJob = vi.spyOn(sessionsQueue, 'getJob'); -// // Execute the job -// await incomingEvent(job); + const timestamp = new Date(); + // Mock job data + const jobData = { + payload: { + geo, + event: { + name: 'test_event', + timestamp: timestamp.toISOString(), + properties: { __path: 'https://example.com/test' }, + }, + headers: { + 'request-id': '123', + 'user-agent': + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', + 'openpanel-sdk-name': 'web', + 'openpanel-sdk-version': '1.0.0', + }, + projectId, + currentDeviceId, + previousDeviceId, + }, + }; -// const event = { -// name: 'test_event', -// deviceId: currentDeviceId, -// // @ts-expect-error -// sessionId: createEvent.mock.calls[1][0].sessionId, -// profileId: '', -// projectId, -// properties: { -// __hash: undefined, -// __query: undefined, -// }, -// createdAt: timestamp, -// country: 'US', -// city: 'New York', -// region: 'NY', -// longitude: 0, -// latitude: 0, -// os: 'Windows', -// osVersion: '10', -// browser: 'Chrome', -// browserVersion: '91.0.4472.124', -// device: 'desktop', -// brand: '', -// model: '', -// duration: 0, -// path: '/test', -// origin: 'https://example.com', -// referrer: '', -// referrerName: '', -// referrerType: 'unknown', -// sdkName: 'web', -// sdkVersion: '1.0.0', -// }; + const job = { data: jobData } as Job; -// expect(sessionsQueue.add.mock.calls[0]).toMatchObject([ -// 'session', -// { -// type: 'createSessionEnd', -// payload: event, -// }, -// { -// delay: SESSION_TIMEOUT, -// jobId: `sessionEnd:${projectId}:${event.deviceId}:${timestamp.getTime()}`, -// }, -// ]); + const changeDelay = vi.fn(); + const updateData = vi.fn(); + spySessionsQueueGetJob.mockResolvedValueOnce({ + getState: vi.fn().mockResolvedValue('delayed'), + updateData, + changeDelay, + data: { + type: 'createSessionEnd', + payload: { + sessionId: 'session-123', + deviceId: currentDeviceId, + profileId: currentDeviceId, + projectId, + }, + }, + } as Partial as Job); + // Execute the job + await incomingEvent(job); -// // Assertions -// // Issue: https://github.com/oven-sh/bun/issues/10380 -// // expect(createEvent).toHaveBeenCalledWith(...) -// expect(createEvent.mock.calls[0]).toMatchObject([ -// { -// name: 'session_start', -// deviceId: currentDeviceId, -// sessionId: expect.stringMatching( -// /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i, -// ), -// profileId: '', -// projectId, -// properties: { -// __hash: undefined, -// __query: undefined, -// }, -// createdAt: new Date(timestamp.getTime() - 100), -// country: 'US', -// city: 'New York', -// region: 'NY', -// longitude: 0, -// latitude: 0, -// os: 'Windows', -// osVersion: '10', -// browser: 'Chrome', -// browserVersion: '91.0.4472.124', -// device: 'desktop', -// brand: '', -// model: '', -// duration: 0, -// path: '/test', -// origin: 'https://example.com', -// referrer: '', -// referrerName: '', -// referrerType: 'unknown', -// sdkName: 'web', -// sdkVersion: '1.0.0', -// }, -// ]); -// expect(createEvent.mock.calls[1]).toMatchObject([event]); + const event = { + name: 'test_event', + deviceId: currentDeviceId, + profileId: '', + sessionId: 'session-123', + projectId, + properties: { + __hash: undefined, + __query: undefined, + __user_agent: jobData.payload.headers['user-agent'], + __reqId: jobData.payload.headers['request-id'], + }, + createdAt: timestamp, + country: 'US', + city: 'New York', + region: 'NY', + longitude: 0, + latitude: 0, + os: 'Windows', + osVersion: '10', + browser: 'Chrome', + browserVersion: '91.0.4472.124', + device: 'desktop', + brand: undefined, + model: undefined, + duration: 0, + path: '/test', + origin: 'https://example.com', + referrer: '', + referrerName: '', + referrerType: 'unknown', + sdkName: jobData.payload.headers['openpanel-sdk-name'], + sdkVersion: jobData.payload.headers['openpanel-sdk-version'], + }; -// // Add more specific assertions based on the expected behavior -// }); + expect(spySessionsQueueAdd).toHaveBeenCalledTimes(0); + expect(changeDelay).toHaveBeenCalledWith(SESSION_TIMEOUT); + expect(createEvent as Mock).toBeCalledTimes(1); + expect((createEvent as Mock).mock.calls[0]![0]).toStrictEqual(event); + }); -// it('should reuse existing session', async () => { -// // Mock job data -// const jobData = { -// payload: { -// geo, -// event: { -// name: 'test_event', -// timestamp: new Date().toISOString(), -// properties: { __path: 'https://example.com/test' }, -// }, -// headers: { -// 'user-agent': -// 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', -// 'openpanel-sdk-name': 'web', -// 'openpanel-sdk-version': '1.0.0', -// }, -// projectId, -// currentDeviceId, -// previousDeviceId, -// priority: false, -// }, -// }; -// const changeDelay = mock(); -// findJobByPrefix.mockReturnValueOnce({ -// changeDelay, -// data: { -// type: 'createSessionEnd', -// payload: { -// sessionId: 'session-123', -// deviceId: currentDeviceId, -// profileId: currentDeviceId, -// projectId, -// }, -// }, -// }); + it('should handle server events (with existing screen view)', async () => { + const timestamp = new Date(); + const jobData = { + payload: { + geo, + event: { + name: 'server_event', + timestamp: timestamp.toISOString(), + properties: { custom_property: 'test_value' }, + profileId: 'profile-123', + }, + headers: { + 'user-agent': 'OpenPanel Server/1.0', + 'openpanel-sdk-name': 'server', + 'openpanel-sdk-version': '1.0.0', + 'request-id': '123', + }, + projectId, + currentDeviceId: '', + previousDeviceId: '', + }, + }; -// const job = { data: jobData } as Job; + const job = { data: jobData } as Job; -// // Execute the job -// await incomingEvent(job); + const mockLastScreenView = { + deviceId: 'last-device-123', + sessionId: 'last-session-456', + country: 'CA', + city: 'Toronto', + region: 'ON', + os: 'iOS', + osVersion: '15.0', + browser: 'Safari', + browserVersion: '15.0', + device: 'mobile', + brand: 'Apple', + model: 'iPhone', + path: '/last-path', + origin: 'https://example.com', + referrer: 'https://google.com', + referrerName: 'Google', + referrerType: 'search', + }; -// expect(changeDelay.mock.calls[0]).toMatchObject([SESSION_TIMEOUT]); + // Mock the eventBuffer.getLastScreenView method + vi.mocked(eventBuffer.getLastScreenView).mockResolvedValueOnce( + mockLastScreenView as IServiceEvent, + ); -// // Assertions -// // Issue: https://github.com/oven-sh/bun/issues/10380 -// // expect(createEvent).toHaveBeenCalledWith(...) -// expect(createEvent.mock.calls[0]).toMatchObject([ -// { -// name: 'test_event', -// deviceId: currentDeviceId, -// profileId: '', -// sessionId: 'session-123', -// projectId, -// properties: { -// __hash: undefined, -// __query: undefined, -// }, -// createdAt: expect.any(Date), -// country: 'US', -// city: 'New York', -// region: 'NY', -// longitude: 0, -// latitude: 0, -// os: 'Windows', -// osVersion: '10', -// browser: 'Chrome', -// browserVersion: '91.0.4472.124', -// device: 'desktop', -// brand: '', -// model: '', -// duration: 0, -// path: '/test', -// origin: 'https://example.com', -// referrer: '', -// referrerName: '', -// referrerType: 'unknown', -// sdkName: 'web', -// sdkVersion: '1.0.0', -// }, -// ]); + await incomingEvent(job); -// // Add more specific assertions based on the expected behavior -// }); + expect((createEvent as Mock).mock.calls[0]![0]).toStrictEqual({ + name: 'server_event', + deviceId: 'last-device-123', + sessionId: 'last-session-456', + profileId: 'profile-123', + projectId, + properties: { + custom_property: 'test_value', + __user_agent: 'OpenPanel Server/1.0', + __reqId: '123', + __hash: undefined, + __query: undefined, + }, + createdAt: timestamp, + country: 'CA', + city: 'Toronto', + region: 'ON', + longitude: 0, + latitude: 0, + os: 'iOS', + osVersion: '15.0', + browser: 'Safari', + browserVersion: '15.0', + device: 'mobile', + brand: 'Apple', + model: 'iPhone', + duration: 0, + path: '/last-path', + origin: 'https://example.com', + referrer: 'https://google.com', + referrerName: 'Google', + referrerType: 'search', + sdkName: 'server', + sdkVersion: '1.0.0', + }); -// it('should handle server events', async () => { -// const timestamp = new Date(); -// const jobData = { -// payload: { -// geo, -// event: { -// name: 'server_event', -// timestamp: timestamp.toISOString(), -// properties: { custom_property: 'test_value' }, -// profileId: 'profile-123', -// }, -// headers: { -// 'user-agent': 'OpenPanel Server/1.0', -// 'openpanel-sdk-name': 'server', -// 'openpanel-sdk-version': '1.0.0', -// }, -// projectId, -// currentDeviceId: '', -// previousDeviceId: '', -// priority: true, -// }, -// }; + expect(sessionsQueue.add).not.toHaveBeenCalled(); + }); -// const job = { data: jobData } as Job; + it('should handle server events (without existing screen view)', async () => { + const timestamp = new Date(); + const jobData = { + payload: { + geo, + event: { + name: 'server_event', + timestamp: timestamp.toISOString(), + properties: { custom_property: 'test_value' }, + profileId: 'profile-123', + }, + headers: { + 'user-agent': 'OpenPanel Server/1.0', + 'openpanel-sdk-name': 'server', + 'openpanel-sdk-version': '1.0.0', + 'request-id': '123', + }, + projectId, + currentDeviceId: '', + previousDeviceId: '', + }, + }; -// const mockLastScreenView = { -// deviceId: 'last-device-123', -// sessionId: 'last-session-456', -// country: 'CA', -// city: 'Toronto', -// region: 'ON', -// os: 'iOS', -// osVersion: '15.0', -// browser: 'Safari', -// browserVersion: '15.0', -// device: 'mobile', -// brand: 'Apple', -// model: 'iPhone', -// path: '/last-path', -// origin: 'https://example.com', -// referrer: 'https://google.com', -// referrerName: 'Google', -// referrerType: 'search', -// }; + const job = { data: jobData } as Job; -// getLastScreenViewFromProfileId.mockReturnValueOnce(mockLastScreenView); + // Mock getLastScreenView to return null + vi.mocked(eventBuffer.getLastScreenView).mockResolvedValueOnce(null); -// await incomingEvent(job); + await incomingEvent(job); -// // expect(getLastScreenViewFromProfileId).toHaveBeenCalledWith({ -// // profileId: 'profile-123', -// // projectId, -// // }); + expect((createEvent as Mock).mock.calls[0]![0]).toStrictEqual({ + name: 'server_event', + deviceId: '', + sessionId: '', + profileId: 'profile-123', + projectId, + properties: { + custom_property: 'test_value', + __user_agent: 'OpenPanel Server/1.0', + __reqId: '123', + __hash: undefined, + __query: undefined, + }, + createdAt: timestamp, + country: 'US', + city: 'New York', + region: 'NY', + longitude: 0, + latitude: 0, + os: '', + osVersion: '', + browser: '', + browserVersion: '', + device: 'server', + brand: '', + model: '', + duration: 0, + path: '', + origin: '', + referrer: undefined, + referrerName: undefined, + referrerType: undefined, + sdkName: 'server', + sdkVersion: '1.0.0', + }); -// expect(createEvent.mock.calls[0]).toMatchObject([ -// { -// name: 'server_event', -// deviceId: 'last-device-123', -// sessionId: 'last-session-456', -// profileId: 'profile-123', -// projectId, -// properties: { -// custom_property: 'test_value', -// user_agent: 'OpenPanel Server/1.0', -// }, -// createdAt: timestamp, -// country: 'CA', -// city: 'Toronto', -// region: 'ON', -// longitude: 0, -// latitude: 0, -// os: 'iOS', -// osVersion: '15.0', -// browser: 'Safari', -// browserVersion: '15.0', -// device: 'mobile', -// brand: 'Apple', -// model: 'iPhone', -// duration: 0, -// path: '/last-path', -// origin: 'https://example.com', -// referrer: 'https://google.com', -// referrerName: 'Google', -// referrerType: 'search', -// sdkName: 'server', -// sdkVersion: '1.0.0', -// }, -// ]); - -// expect(sessionsQueue.add).not.toHaveBeenCalled(); -// expect(findJobByPrefix).not.toHaveBeenCalled(); -// }); - -// // Add more test cases for different scenarios: -// // - Server events -// // - Existing sessions -// // - Different priorities -// // - Error cases -// }); + expect(sessionsQueue.add).not.toHaveBeenCalled(); + }); +}); diff --git a/apps/worker/src/referrers/index.ts b/apps/worker/src/referrers/index.ts index 3bcba5ee..6d1734d3 100644 --- a/apps/worker/src/referrers/index.ts +++ b/apps/worker/src/referrers/index.ts @@ -2663,8 +2663,8 @@ const referrers: Record = { 'com.laurencedawson.reddit_sync': { type: 'social', name: 'Reddit' }, 'com.laurencedawson.reddit_sync.pro': { type: 'social', name: 'Reddit' }, 'viadeo.com': { type: 'social', name: 'Viadeo' }, - 'github.com': { type: 'social', name: 'GitHub' }, - 'stackoverflow.com': { type: 'social', name: 'StackOverflow' }, + 'github.com': { type: 'tech', name: 'GitHub' }, + 'stackoverflow.com': { type: 'tech', name: 'Stack Overflow' }, 'gaiaonline.com': { type: 'social', name: 'Gaia Online' }, 'stumbleupon.com': { type: 'social', name: 'StumbleUpon' }, 'inci.sozlukspot.com': { type: 'social', name: 'Inci Sozluk' }, @@ -2680,5 +2680,38 @@ const referrers: Record = { 'hyves.nl': { type: 'social', name: 'Hyves' }, 'paper.li': { type: 'social', name: 'Paper.li' }, 'moikrug.ru': { type: 'social', name: 'MoiKrug.ru' }, + 'zoom.us': { type: 'social', name: 'Zoom' }, + 'apple.com': { type: 'tech', name: 'Apple' }, + 'adobe.com': { type: 'tech', name: 'Adobe' }, + 'figma.com': { type: 'tech', name: 'Figma' }, + 'wix.com': { type: 'commerce', name: 'Wix' }, + 'gmail.com': { type: 'email', name: 'Gmail' }, + 'notion.so': { type: 'tech', name: 'Notion' }, + 'ebay.com': { type: 'commerce', name: 'eBay' }, + 'gitlab.com': { type: 'tech', name: 'GitLab' }, + 'slack.com': { type: 'social', name: 'Slack' }, + 'etsy.com': { type: 'commerce', name: 'Etsy' }, + 'bsky.app': { type: 'social', name: 'Bluesky' }, + 'twitch.tv': { type: 'content', name: 'Twitch' }, + 'dropbox.com': { type: 'tech', name: 'Dropbox' }, + 'outlook.com': { type: 'email', name: 'Outlook' }, + 'medium.com': { type: 'content', name: 'Medium' }, + 'paypal.com': { type: 'commerce', name: 'PayPal' }, + 'discord.com': { type: 'social', name: 'Discord' }, + 'stripe.com': { type: 'commerce', name: 'Stripe' }, + 'spotify.com': { type: 'content', name: 'Spotify' }, + 'netflix.com': { type: 'content', name: 'Netflix' }, + 'whatsapp.com': { type: 'social', name: 'WhatsApp' }, + 'shopify.com': { type: 'commerce', name: 'Shopify' }, + 'microsoft.com': { type: 'tech', name: 'Microsoft' }, + 'alibaba.com': { type: 'commerce', name: 'Alibaba' }, + 'telegram.org': { type: 'social', name: 'Telegram' }, + 'substack.com': { type: 'content', name: 'Substack' }, + 'salesforce.com': { type: 'tech', name: 'Salesforce' }, + 'wikipedia.org': { type: 'content', name: 'Wikipedia' }, + 'mastodon.social': { type: 'social', name: 'Mastodon' }, + 'office.com': { type: 'tech', name: 'Microsoft Office' }, + 'squarespace.com': { type: 'commerce', name: 'Squarespace' }, + 'teams.microsoft.com': { type: 'social', name: 'Microsoft Teams' }, } as const; export default referrers; diff --git a/apps/worker/src/utils/parse-referrer.test.ts b/apps/worker/src/utils/parse-referrer.test.ts new file mode 100644 index 00000000..66d17c54 --- /dev/null +++ b/apps/worker/src/utils/parse-referrer.test.ts @@ -0,0 +1,117 @@ +import { describe, expect, it } from 'vitest'; +import { getReferrerWithQuery, parseReferrer } from './parse-referrer'; + +describe('parseReferrer', () => { + it('should handle undefined or empty URLs', () => { + expect(parseReferrer(undefined)).toEqual({ + name: '', + type: 'unknown', + url: '', + }); + + expect(parseReferrer('')).toEqual({ + name: '', + type: 'unknown', + url: '', + }); + }); + + it('should parse valid referrer URLs', () => { + expect(parseReferrer('https://google.com/search?q=test')).toEqual({ + name: 'Google', + type: 'search', + url: 'https://google.com/search?q=test', + }); + }); + + it('should handle www prefix in hostnames', () => { + expect(parseReferrer('https://www.twitter.com/user')).toEqual({ + name: 'Twitter', + type: 'social', + url: 'https://www.twitter.com/user', + }); + + expect(parseReferrer('https://twitter.com/user')).toEqual({ + name: 'Twitter', + type: 'social', + url: 'https://twitter.com/user', + }); + }); + + it('should handle unknown referrers', () => { + expect(parseReferrer('https://unknown-site.com')).toEqual({ + name: '', + type: 'unknown', + url: 'https://unknown-site.com', + }); + }); + + it('should handle invalid URLs', () => { + expect(parseReferrer('not-a-url')).toEqual({ + name: '', + type: 'unknown', + url: 'not-a-url', + }); + }); +}); + +describe('getReferrerWithQuery', () => { + it('should handle undefined or empty query', () => { + expect(getReferrerWithQuery(undefined)).toBeNull(); + expect(getReferrerWithQuery({})).toBeNull(); + }); + + it('should parse utm_source parameter', () => { + expect(getReferrerWithQuery({ utm_source: 'google' })).toEqual({ + name: 'Google', + type: 'unknown', + url: '', + }); + }); + + it('should parse ref parameter', () => { + expect(getReferrerWithQuery({ ref: 'facebook' })).toEqual({ + name: 'Facebook', + type: 'social', + url: '', + }); + }); + + it('should parse utm_referrer parameter', () => { + expect(getReferrerWithQuery({ utm_referrer: 'twitter' })).toEqual({ + name: 'Twitter', + type: 'social', + url: '', + }); + }); + + it('should handle case-insensitive matching', () => { + expect(getReferrerWithQuery({ utm_source: 'GoOgLe' })).toEqual({ + name: 'Google', + type: 'unknown', + url: '', + }); + }); + + it('should handle unknown sources', () => { + expect(getReferrerWithQuery({ utm_source: 'unknown-source' })).toEqual({ + name: 'unknown-source', + type: 'unknown', + url: '', + }); + }); + + it('should prioritize utm_source over ref and utm_referrer', () => { + expect( + getReferrerWithQuery({ + utm_source: 'google', + ref: 'facebook', + utm_referrer: 'twitter', + }), + ).toEqual({ + name: 'Google', + type: 'unknown', + url: '', + }); + }); +}); diff --git a/apps/worker/src/utils/session-handler.ts b/apps/worker/src/utils/session-handler.ts index acb858f7..03877826 100644 --- a/apps/worker/src/utils/session-handler.ts +++ b/apps/worker/src/utils/session-handler.ts @@ -76,7 +76,7 @@ export async function getSessionEnd({ sessionEnd.job.data.payload.deviceId; const eventIsIdentified = - sessionEnd.job.data.payload.profileId !== profileId; + profileId && sessionEnd.job.data.payload.profileId !== profileId; if (existingSessionIsAnonymous && eventIsIdentified) { await sessionEnd.job.updateData({ diff --git a/apps/worker/vitest.config.ts b/apps/worker/vitest.config.ts new file mode 100644 index 00000000..f87a2039 --- /dev/null +++ b/apps/worker/vitest.config.ts @@ -0,0 +1,3 @@ +import { getSharedVitestConfig } from '../../vitest.shared'; + +export default getSharedVitestConfig({ __dirname }); diff --git a/package.json b/package.json index 141e749f..f6e226de 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "author": "Carl-Gerhard Lindesvärd", "packageManager": "pnpm@9.15.0", "scripts": { + "test": "vitest", "dock:up": "docker compose up -d", "dock:down": "docker compose down", "dock:ch": "docker compose exec -it op-ch clickhouse-client -d openpanel", @@ -25,7 +26,7 @@ "update-simple-git-hooks": "npx simple-git-hooks" }, "simple-git-hooks": { - "pre-push": "pnpm typecheck" + "pre-push": "pnpm typecheck && pnpm test" }, "dependencies": { "@hyperdx/node-opentelemetry": "^0.8.1", @@ -48,6 +49,7 @@ ], "devDependencies": { "@biomejs/biome": "1.9.1", - "simple-git-hooks": "^2.12.1" + "simple-git-hooks": "^2.12.1", + "vitest": "^3.0.4" } } diff --git a/packages/common/package.json b/packages/common/package.json index 4bbdfdfa..d307325b 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -3,6 +3,7 @@ "version": "0.0.1", "main": "index.ts", "scripts": { + "test": "vitest", "typecheck": "tsc --noEmit" }, "dependencies": { diff --git a/packages/common/server/parser-user-agent.test.ts b/packages/common/server/parser-user-agent.test.ts new file mode 100644 index 00000000..aa5e1c0b --- /dev/null +++ b/packages/common/server/parser-user-agent.test.ts @@ -0,0 +1,170 @@ +import { describe, expect, it } from 'vitest'; +import { getDevice, parseUserAgent } from './parser-user-agent'; + +describe('parseUserAgent', () => { + it('should return server UA for null/undefined input', () => { + const serverUa = { + isServer: true, + device: 'server', + os: '', + osVersion: '', + browser: '', + browserVersion: '', + brand: '', + model: '', + }; + + expect(parseUserAgent(null)).toEqual(serverUa); + expect(parseUserAgent(undefined)).toEqual(serverUa); + }); + + it('should parse iPhone user agents', () => { + const ua = + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5 Mobile/15E148 Safari/604.1'; + + expect(parseUserAgent(ua)).toEqual({ + isServer: false, + device: 'mobile', + os: 'iOS', + osVersion: '16.5', + browser: 'Mobile Safari', + browserVersion: '16.5', + brand: 'Apple', + model: 'iPhone', + }); + }); + + it('should parse iPad user agents', () => { + const ua = + 'Mozilla/5.0 (iPad; CPU OS 16_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5 Mobile/15E148 Safari/604.1'; + + expect(parseUserAgent(ua)).toEqual({ + isServer: false, + device: 'tablet', + os: 'iOS', + osVersion: '16.5', + browser: 'Mobile Safari', + browserVersion: '16.5', + brand: 'Apple', + model: 'iPad', + }); + }); + + it('should parse iPadOS user agents', () => { + const ua = + 'Mozilla/5.0 (iPad; iPadOS 18_0; like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/18.0'; + + expect(parseUserAgent(ua)).toEqual({ + isServer: false, + device: 'tablet', + os: 'Mac OS', + osVersion: '18.0', + browser: 'WebKit', + browserVersion: '605.1.15', + brand: 'Apple', + model: 'iPad', + }); + }); + + it('should parse desktop Chrome user agents', () => { + const ua = + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'; + + expect(parseUserAgent(ua)).toEqual({ + isServer: false, + device: 'desktop', + os: 'Windows', + osVersion: '10', + browser: 'Chrome', + browserVersion: '91.0.4472.124', + brand: undefined, + model: undefined, + }); + }); + + it('should handle server user agents', () => { + const serverUas = [ + 'Go-http-client/1.0', + 'Go Http Client/1.0', + 'node-fetch/1.0', + ]; + + const expectedResult = { + isServer: true, + device: 'server', + os: '', + osVersion: '', + browser: '', + browserVersion: '', + brand: '', + model: '', + }; + + serverUas.forEach((ua) => { + expect(parseUserAgent(ua)).toEqual(expectedResult); + }); + }); + + it('should apply overrides when provided', () => { + const ua = + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15'; + const overrides = { + __os: 'Custom OS', + __osVersion: '1.0', + __browser: 'Custom Browser', + __browserVersion: '2.0', + __device: 'custom-device', + __brand: 'Custom Brand', + __model: 'Custom Model', + }; + + expect(parseUserAgent(ua, overrides)).toEqual({ + isServer: false, + device: 'custom-device', + os: 'Custom OS', + osVersion: '1.0', + browser: 'Custom Browser', + browserVersion: '2.0', + brand: 'Custom Brand', + model: 'Custom Model', + }); + }); +}); + +describe('getDevice', () => { + it('should detect mobile devices', () => { + const mobileUas = [ + 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_5 like Mac OS X) AppleWebKit/605.1.15', + 'Mozilla/5.0 (Linux; Android 10; SM-A505FN) AppleWebKit/537.36', + 'Mozilla/5.0 (Linux; U; Android 4.0.3; ko-kr; LG-L160L Build/IML74K) AppleWebkit/534.30', + ]; + + mobileUas.forEach((ua) => { + expect(getDevice(ua)).toBe('mobile'); + }); + }); + + it('should detect tablet devices', () => { + const tabletUas = [ + 'Mozilla/5.0 (iPad; CPU OS 16_5 like Mac OS X) AppleWebKit/605.1.15', + 'Mozilla/5.0 (Linux; Android 10.0; Tablet; rv:68.0) Gecko/68.0 Firefox/68.0', + 'Mozilla/5.0 (Linux; Android 7.0; SM-T827R4 Build/NRD90M)', + ]; + + tabletUas.forEach((ua) => { + expect(getDevice(ua)).toBe('tablet'); + }); + }); + + it('should default to desktop for non-mobile/tablet devices', () => { + const desktopUas = [ + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36', + 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36', + ]; + + desktopUas.forEach((ua) => { + expect(getDevice(ua)).toBe('desktop'); + }); + }); +}); diff --git a/packages/common/server/parser-user-agent.ts b/packages/common/server/parser-user-agent.ts index 13de58f6..b84b9768 100644 --- a/packages/common/server/parser-user-agent.ts +++ b/packages/common/server/parser-user-agent.ts @@ -109,6 +109,21 @@ function isServer(res: UAParser.IResult) { } export function getDevice(ua: string) { + // Samsung mobile devices use SM-[A,G,N,etc]XXX pattern + if (/SM-[ABDEFGJMNRWZ][0-9]+/i.test(ua)) { + return 'mobile'; + } + + // Samsung tablets use SM-TXXX pattern + if (/SM-T[0-9]+/i.test(ua)) { + return 'tablet'; + } + + // LG mobile devices use LG-XXXX pattern + if (/LG-[A-Z0-9]+/i.test(ua)) { + return 'mobile'; + } + const mobile1 = /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test( ua, @@ -118,9 +133,11 @@ export function getDevice(ua: string) { ua.slice(0, 4), ); const tablet = - /tablet|ipad|android(?!.*mobile)|xoom|sch-i800|kindle|silk|playbook/i.test( - ua, - ); + /tablet|ipad|xoom|sch-i800|kindle|silk|playbook/i.test(ua) || + (/android/i.test(ua) && + !/mobile/i.test(ua) && + !/SM-[ABDEFGJMNRWZ][0-9]+/i.test(ua) && + !/LG-[A-Z0-9]+/i.test(ua)); if (mobile1 || mobile2) { return 'mobile'; diff --git a/packages/common/vitest.config.ts b/packages/common/vitest.config.ts new file mode 100644 index 00000000..f87a2039 --- /dev/null +++ b/packages/common/vitest.config.ts @@ -0,0 +1,3 @@ +import { getSharedVitestConfig } from '../../vitest.shared'; + +export default getSharedVitestConfig({ __dirname }); diff --git a/packages/logger/index.ts b/packages/logger/index.ts index 3f71c5df..25132adc 100644 --- a/packages/logger/index.ts +++ b/packages/logger/index.ts @@ -85,7 +85,7 @@ export function createLogger({ name }: { name: string }): ILogger { level: logLevel, format, transports, - // silent: true, + silent: process.env.NODE_ENV === 'test', // Add ISO levels of logging from PINO levels: Object.assign( { fatal: 0, warn: 4, trace: 7 }, diff --git a/packages/queue/index.ts b/packages/queue/index.ts index 773320ba..fe9b3314 100644 --- a/packages/queue/index.ts +++ b/packages/queue/index.ts @@ -1,4 +1,3 @@ export * from './src/queues'; export type * from './src/queues'; -export { findJobByPrefix } from './src/utils'; export type { JobsOptions } from 'bullmq'; diff --git a/packages/queue/src/utils.ts b/packages/queue/src/utils.ts deleted file mode 100644 index 5518a4cb..00000000 --- a/packages/queue/src/utils.ts +++ /dev/null @@ -1,40 +0,0 @@ -import type { Queue } from 'bullmq'; - -export async function findJobByPrefix( - queue: Queue, - keys: string[], - matcher: string, -) { - const getTime = (val?: string) => { - if (!val) return null; - const match = val.match(/:(\d+)$/); - return match?.[1] ? Number.parseInt(match[1], 10) : null; - }; - const filtered = keys - .filter((key) => key.includes(matcher)) - .filter((key) => getTime(key)); - filtered.sort((a, b) => { - const aTime = getTime(a); - const bTime = getTime(b); - if (aTime === null) return 1; - if (bTime === null) return -1; - return aTime - bTime; - }); - - async function getJob(index: number) { - if (index >= filtered.length) return null; - - const key = filtered[index]?.replace(/^bull:(\w+):/, ''); - // return new Promise((resolve) => ) - if (key) { - const job = await queue.getJob(key); - if ((await job?.getState()) === 'delayed') { - return job; - } - } - - return getJob(index + 1); - } - - return getJob(0); -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4e1729ab..0dae586e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -36,6 +36,9 @@ importers: simple-git-hooks: specifier: ^2.12.1 version: 2.12.1 + vitest: + specifier: ^3.0.4 + version: 3.1.3(@types/debug@4.1.12)(@types/node@20.14.8)(jiti@2.4.1)(terser@5.27.1) apps/api: dependencies: @@ -6649,6 +6652,35 @@ packages: peerDependencies: graphql: ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 + '@vitest/expect@3.1.3': + resolution: {integrity: sha512-7FTQQuuLKmN1Ig/h+h/GO+44Q1IlglPlR2es4ab7Yvfx+Uk5xsv+Ykk+MEt/M2Yn/xGmzaLKxGw2lgy2bwuYqg==} + + '@vitest/mocker@3.1.3': + resolution: {integrity: sha512-PJbLjonJK82uCWHjzgBJZuR7zmAOrSvKk1QBxrennDIgtH4uK0TB1PvYmc0XBCigxxtiAVPfWtAdy4lpz8SQGQ==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 || ^6.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@3.1.3': + resolution: {integrity: sha512-i6FDiBeJUGLDKADw2Gb01UtUNb12yyXAqC/mmRWuYl+m/U9GS7s8us5ONmGkGpUUo7/iAYzI2ePVfOZTYvUifA==} + + '@vitest/runner@3.1.3': + resolution: {integrity: sha512-Tae+ogtlNfFei5DggOsSUvkIaSuVywujMj6HzR97AHK6XK8i3BuVyIifWAm/sE3a15lF5RH9yQIrbXYuo0IFyA==} + + '@vitest/snapshot@3.1.3': + resolution: {integrity: sha512-XVa5OPNTYUsyqG9skuUkFzAeFnEzDp8hQu7kZ0N25B1+6KjGm4hWLtURyBbsIAOekfWQ7Wuz/N/XXzgYO3deWQ==} + + '@vitest/spy@3.1.3': + resolution: {integrity: sha512-x6w+ctOEmEXdWaa6TO4ilb7l9DxPR5bwEb6hILKuxfU1NqWT2mpJD9NJN7t3OTfxmVlOMrvtoFJGdgyzZ605lQ==} + + '@vitest/utils@3.1.3': + resolution: {integrity: sha512-2Ltrpht4OmHO9+c/nmHtF09HWiyWdworqnHIwjfvDyWjuwKbdkcS9AnhsDn+8E2RM4x++foD1/tNuLPVvWG1Rg==} + '@xmldom/xmldom@0.7.13': resolution: {integrity: sha512-lm2GW5PkosIzccsaZIz7tp8cPADSIlIHWDFTR1N0SzfinhhYgeIQjFMz4rYzanCScr3DqQLeomUDArp6MWKm+g==} engines: {node: '>=10.0.0'} @@ -6843,6 +6875,10 @@ packages: asap@2.0.6: resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + ast-types@0.15.2: resolution: {integrity: sha512-c27loCv9QkZinsa5ProX751khO9DJl/AcB5c2KNtA6NRvHKS0PgLfcftz72KVq504vB0Gku5s2kUZzDBvQWvHg==} engines: {node: '>=4'} @@ -7170,6 +7206,10 @@ packages: ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + chai@5.2.0: + resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==} + engines: {node: '>=12'} + chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -7209,6 +7249,10 @@ packages: charenc@0.0.2: resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} + check-error@2.1.1: + resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} + engines: {node: '>= 16'} + cheerio-select@2.1.0: resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} @@ -7810,6 +7854,10 @@ packages: decode-named-character-reference@1.0.2: resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==} + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + deep-extend@0.6.0: resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} engines: {node: '>=4.0.0'} @@ -8229,6 +8277,10 @@ packages: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} + expect-type@1.2.1: + resolution: {integrity: sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==} + engines: {node: '>=12.0.0'} + expo-application@5.3.1: resolution: {integrity: sha512-HR2+K+Hm33vLw/TfbFaHrvUbRRNRco8R+3QaCKy7eJC2LFfT05kZ15ynGaKfB5DJ/oqPV3mxXVR/EfwmE++hoA==} peerDependencies: @@ -9692,6 +9744,9 @@ packages: lottie-web@5.12.2: resolution: {integrity: sha512-uvhvYPC8kGPjXT3MyKMrL3JitEAmDMp30lVkuq/590Mw9ok6pWcFCwXJveo0t5uqYw1UREQHofD+jVpdjBv8wg==} + loupe@3.1.3: + resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==} + lowlight@1.20.0: resolution: {integrity: sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==} @@ -10719,6 +10774,13 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + pathval@2.0.0: + resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} + engines: {node: '>= 14.16'} + peberminta@0.9.0: resolution: {integrity: sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==} @@ -11853,6 +11915,9 @@ packages: resolution: {integrity: sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==} engines: {node: '>= 0.4'} + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -11974,6 +12039,9 @@ packages: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + stackframe@1.3.4: resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} @@ -11995,6 +12063,9 @@ packages: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} + std-env@3.9.0: + resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} + stop-iteration-iterator@1.0.0: resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==} engines: {node: '>= 0.4'} @@ -12290,6 +12361,9 @@ packages: resolution: {integrity: sha512-27BIW0dIWTYYoWNnqSmoNMKe5WIbkXsc0xaCQHd3/3xT2XMuMJrzHdrO9QBFR14emBz1Bu0dOAs2sCBBrvgPQA==} engines: {node: '>=12'} + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} @@ -12297,6 +12371,18 @@ packages: resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==} engines: {node: '>=12.0.0'} + tinypool@1.0.2: + resolution: {integrity: sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@2.0.0: + resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} + engines: {node: '>=14.0.0'} + + tinyspy@3.0.2: + resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==} + engines: {node: '>=14.0.0'} + tmp@0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} @@ -12757,6 +12843,11 @@ packages: victory-vendor@36.9.1: resolution: {integrity: sha512-+pZIP+U3pEJdDCeFmsXwHzV7vNHQC/eIbHklfe2ZCZqayYRH7lQbHcVgsJ0XOOv27hWs4jH4MONgXxHMObTMSA==} + vite-node@3.1.3: + resolution: {integrity: sha512-uHV4plJ2IxCl4u1up1FQRrqclylKAogbtBfOTwcuJ28xFi+89PZ57BRh+naIRvH70HPwxy5QHYzg1OrEaC7AbA==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + vite@6.3.3: resolution: {integrity: sha512-5nXH+QsELbFKhsEfWLkHrvgRpTdGJzqOZ+utSdmPTvwHmvU6ITTm3xx+mRusihkcI8GeC7lCDyn3kDtiki9scw==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -12805,6 +12896,34 @@ packages: vite: optional: true + vitest@3.1.3: + resolution: {integrity: sha512-188iM4hAHQ0km23TN/adso1q5hhwKqUpv+Sd6p5sOuh6FhQnRNW3IsiIpvxqahtBabsJ2SLZgmGSpcYK4wQYJw==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/debug': ^4.1.12 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@vitest/browser': 3.1.3 + '@vitest/ui': 3.1.3 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/debug': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + vlq@1.0.1: resolution: {integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==} @@ -12871,6 +12990,11 @@ packages: engines: {node: '>= 8'} hasBin: true + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + wide-align@1.1.5: resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} @@ -14701,7 +14825,7 @@ snapshots: '@expo/sdk-runtime-versions': 1.0.0 '@react-native/normalize-color': 2.1.0 chalk: 4.1.2 - debug: 4.3.7 + debug: 4.4.0 find-up: 5.0.0 getenv: 1.0.0 glob: 7.1.6 @@ -14764,7 +14888,7 @@ snapshots: dependencies: '@expo/spawn-async': 1.7.2 chalk: 4.1.2 - debug: 4.3.7 + debug: 4.4.0 find-up: 5.0.0 minimatch: 3.1.2 p-limit: 3.1.0 @@ -15220,7 +15344,7 @@ snapshots: '@jridgewell/gen-mapping@0.3.5': dependencies: '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/trace-mapping': 0.3.25 '@jridgewell/resolve-uri@3.1.2': {} @@ -15241,12 +15365,12 @@ snapshots: '@jridgewell/trace-mapping@0.3.22': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.0 '@js-sdsl/ordered-map@4.4.2': {} @@ -19067,6 +19191,46 @@ snapshots: graphql: 15.8.0 wonka: 4.0.15 + '@vitest/expect@3.1.3': + dependencies: + '@vitest/spy': 3.1.3 + '@vitest/utils': 3.1.3 + chai: 5.2.0 + tinyrainbow: 2.0.0 + + '@vitest/mocker@3.1.3(vite@6.3.3(@types/node@20.14.8)(jiti@2.4.1)(terser@5.27.1))': + dependencies: + '@vitest/spy': 3.1.3 + estree-walker: 3.0.3 + magic-string: 0.30.17 + optionalDependencies: + vite: 6.3.3(@types/node@20.14.8)(jiti@2.4.1)(terser@5.27.1) + + '@vitest/pretty-format@3.1.3': + dependencies: + tinyrainbow: 2.0.0 + + '@vitest/runner@3.1.3': + dependencies: + '@vitest/utils': 3.1.3 + pathe: 2.0.3 + + '@vitest/snapshot@3.1.3': + dependencies: + '@vitest/pretty-format': 3.1.3 + magic-string: 0.30.17 + pathe: 2.0.3 + + '@vitest/spy@3.1.3': + dependencies: + tinyspy: 3.0.2 + + '@vitest/utils@3.1.3': + dependencies: + '@vitest/pretty-format': 3.1.3 + loupe: 3.1.3 + tinyrainbow: 2.0.0 + '@xmldom/xmldom@0.7.13': {} '@xmldom/xmldom@0.8.10': {} @@ -19100,13 +19264,13 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.3.7 + debug: 4.4.0 transitivePeerDependencies: - supports-color agent-base@7.1.1: dependencies: - debug: 4.3.7 + debug: 4.4.0 transitivePeerDependencies: - supports-color @@ -19276,6 +19440,8 @@ snapshots: asap@2.0.6: {} + assertion-error@2.0.1: {} + ast-types@0.15.2: dependencies: tslib: 2.7.0 @@ -19791,6 +19957,14 @@ snapshots: ccount@2.0.1: {} + chai@5.2.0: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.1 + deep-eql: 5.0.2 + loupe: 3.1.3 + pathval: 2.0.0 + chalk@2.4.2: dependencies: ansi-styles: 3.2.1 @@ -19822,6 +19996,8 @@ snapshots: charenc@0.0.2: {} + check-error@2.1.1: {} + cheerio-select@2.1.0: dependencies: boolbase: 1.0.0 @@ -20437,6 +20613,8 @@ snapshots: dependencies: character-entities: 2.0.2 + deep-eql@5.0.2: {} + deep-extend@0.6.0: {} deepmerge@4.3.1: {} @@ -21036,6 +21214,8 @@ snapshots: signal-exit: 3.0.7 strip-final-newline: 2.0.0 + expect-type@1.2.1: {} + expo-application@5.3.1(expo@50.0.7(@babel/core@7.24.5)(@react-native/babel-preset@0.73.21(@babel/core@7.24.5)(@babel/preset-env@7.23.9(@babel/core@7.24.5)))): dependencies: expo: 50.0.7(@babel/core@7.24.5)(@react-native/babel-preset@0.73.21(@babel/core@7.24.5)(@babel/preset-env@7.23.9(@babel/core@7.24.5))) @@ -22090,7 +22270,7 @@ snapshots: https-proxy-agent@7.0.5: dependencies: agent-base: 7.1.1 - debug: 4.3.7 + debug: 4.4.0 transitivePeerDependencies: - supports-color @@ -22836,6 +23016,8 @@ snapshots: lottie-web@5.12.2: {} + loupe@3.1.3: {} + lowlight@1.20.0: dependencies: fault: 1.0.4 @@ -23563,7 +23745,7 @@ snapshots: micromark@4.0.0: dependencies: '@types/debug': 4.1.12 - debug: 4.3.7 + debug: 4.4.0 decode-named-character-reference: 1.0.2 devlop: 1.1.0 micromark-core-commonmark: 2.0.1 @@ -24257,6 +24439,10 @@ snapshots: path-type@4.0.0: {} + pathe@2.0.3: {} + + pathval@2.0.0: {} + peberminta@0.9.0: {} peek-stream@1.1.3: @@ -25800,6 +25986,8 @@ snapshots: get-intrinsic: 1.2.4 object-inspect: 1.13.1 + siginfo@2.0.0: {} + signal-exit@3.0.7: {} signal-exit@4.1.0: {} @@ -25921,6 +26109,8 @@ snapshots: dependencies: escape-string-regexp: 2.0.0 + stackback@0.0.2: {} + stackframe@1.3.4: {} stacktrace-parser@0.1.10: @@ -25938,6 +26128,8 @@ snapshots: statuses@2.0.1: {} + std-env@3.9.0: {} + stop-iteration-iterator@1.0.0: dependencies: internal-slot: 1.0.7 @@ -26328,6 +26520,8 @@ snapshots: tiny-lru@11.2.11: {} + tinybench@2.9.0: {} + tinyexec@0.3.2: {} tinyglobby@0.2.13: @@ -26335,6 +26529,12 @@ snapshots: fdir: 6.4.4(picomatch@4.0.2) picomatch: 4.0.2 + tinypool@1.0.2: {} + + tinyrainbow@2.0.0: {} + + tinyspy@3.0.2: {} + tmp@0.0.33: dependencies: os-tmpdir: 1.0.2 @@ -26799,6 +26999,27 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 + vite-node@3.1.3(@types/node@20.14.8)(jiti@2.4.1)(terser@5.27.1): + dependencies: + cac: 6.7.14 + debug: 4.4.0 + es-module-lexer: 1.7.0 + pathe: 2.0.3 + vite: 6.3.3(@types/node@20.14.8)(jiti@2.4.1)(terser@5.27.1) + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + vite@6.3.3(@types/node@20.14.8)(jiti@2.4.1)(terser@5.27.1): dependencies: esbuild: 0.25.3 @@ -26817,6 +27038,46 @@ snapshots: optionalDependencies: vite: 6.3.3(@types/node@20.14.8)(jiti@2.4.1)(terser@5.27.1) + vitest@3.1.3(@types/debug@4.1.12)(@types/node@20.14.8)(jiti@2.4.1)(terser@5.27.1): + dependencies: + '@vitest/expect': 3.1.3 + '@vitest/mocker': 3.1.3(vite@6.3.3(@types/node@20.14.8)(jiti@2.4.1)(terser@5.27.1)) + '@vitest/pretty-format': 3.1.3 + '@vitest/runner': 3.1.3 + '@vitest/snapshot': 3.1.3 + '@vitest/spy': 3.1.3 + '@vitest/utils': 3.1.3 + chai: 5.2.0 + debug: 4.4.0 + expect-type: 1.2.1 + magic-string: 0.30.17 + pathe: 2.0.3 + std-env: 3.9.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.13 + tinypool: 1.0.2 + tinyrainbow: 2.0.0 + vite: 6.3.3(@types/node@20.14.8)(jiti@2.4.1)(terser@5.27.1) + vite-node: 3.1.3(@types/node@20.14.8)(jiti@2.4.1)(terser@5.27.1) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/debug': 4.1.12 + '@types/node': 20.14.8 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + vlq@1.0.1: {} walker@1.0.8: @@ -26892,6 +27153,11 @@ snapshots: dependencies: isexe: 2.0.0 + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + wide-align@1.1.5: dependencies: string-width: 4.2.3 diff --git a/vitest.shared.ts b/vitest.shared.ts new file mode 100644 index 00000000..2551b83c --- /dev/null +++ b/vitest.shared.ts @@ -0,0 +1,27 @@ +import * as path from 'node:path'; +import { defineConfig } from 'vitest/config'; + +export const getSharedVitestConfig = ({ + __dirname: dirname, +}: { __dirname: string }) => { + return defineConfig({ + resolve: { + alias: { + '@': path.resolve(dirname, 'src'), + }, + }, + test: { + env: { + // Not used, just so prisma is happy + DATABASE_URL: 'postgresql://u:p@127.0.0.1:5432/db', + }, + include: ['**/*.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + browser: { + name: 'chromium', + provider: 'playwright', + headless: true, + }, + fakeTimers: { toFake: undefined }, + }, + }); +}; diff --git a/vitest.workspace.ts b/vitest.workspace.ts new file mode 100644 index 00000000..779844e4 --- /dev/null +++ b/vitest.workspace.ts @@ -0,0 +1 @@ +export default ['packages/*', 'apps/*'];