jobs-referer-parser 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/.DS_Store ADDED
Binary file
@@ -0,0 +1,29 @@
1
+ # Copyright (c) 2012-2013 Snowplow Analytics Ltd. All rights reserved.
2
+ #
3
+ # This program is licensed to you under the Apache License Version 2.0,
4
+ # and you may not use this file except in compliance with the Apache License Version 2.0.
5
+ # You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
6
+ #
7
+ # Unless required by applicable law or agreed to in writing,
8
+ # software distributed under the Apache License Version 2.0 is distributed on an
9
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
11
+
12
+ # Author:: Yali Sassoon (mailto:support@snowplowanalytics.com)
13
+ # Copyright:: Copyright (c) 2012-2013 Snowplow Analytics Ltd
14
+ # License:: Apache License Version 2.0
15
+
16
+ module RefererParser
17
+
18
+ class RefererParserError < StandardError
19
+ attr_reader :original
20
+ def initialize(msg, original=nil);
21
+ super(msg);
22
+ @original = original;
23
+ end
24
+ end
25
+
26
+ class UnsupportedFormatError < RefererParserError; end
27
+ class InvalidUriError < RefererParserError; end
28
+ class CorruptReferersError < RefererParserError; end
29
+ end
@@ -0,0 +1,215 @@
1
+ # Copyright (c) 2014 Inside Systems, Inc All rights reserved.
2
+ #
3
+ # This program is licensed to you under the Apache License Version 2.0,
4
+ # and you may not use this file except in compliance with the Apache License Version 2.0.
5
+ # You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
6
+ #
7
+ # Unless required by applicable law or agreed to in writing,
8
+ # software distributed under the Apache License Version 2.0 is distributed on an
9
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
11
+
12
+ # Author:: Kelley Reynolds (mailto:kelley@insidesystems.net)
13
+ # Copyright:: Copyright (c) 2014 Inside Systems Inc
14
+ # License:: Apache License Version 2.0
15
+
16
+ require 'uri'
17
+ require 'cgi'
18
+
19
+ module RefererParser
20
+ class Parser
21
+ DefaultFile = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'data', 'referers.json'))
22
+
23
+ # Create a new parser from one or more filenames/uris, defaults to ../data/referers.json
24
+ def initialize(uris=DefaultFile)
25
+ @domain_index ||= {}
26
+ @name_hash ||= {}
27
+
28
+ update(uris)
29
+ end
30
+
31
+ # Update the referer database with one or more uris
32
+ def update(uris)
33
+ [uris].flatten.each do |uri|
34
+ deserialize_referer_data(read_referer_data(uri), File.extname(uri).downcase)
35
+ end
36
+
37
+ true
38
+ end
39
+
40
+ # Clean out the database
41
+ def clear!
42
+ @domain_index, @name_hash = {}, {}
43
+
44
+ true
45
+ end
46
+
47
+ # Add a referer to the database with medium, name, domain or array of domains, and a parameter or array of parameters
48
+ # If called manually and a domain is added to an existing entry with a path, you may need to call optimize_index! afterwards.
49
+ def add_referer(medium, name, domains, parameters=nil)
50
+ # The same name can be used with multiple mediums so we make a key here
51
+ name_key = "#{name}-#{medium}"
52
+
53
+ # Update the name has with the parameter and medium data
54
+ @name_hash[name_key] = {:source => name, :medium => medium, :parameters => [parameters].flatten }
55
+
56
+ # Update the domain to name index
57
+ [domains].flatten.each do |domain_url|
58
+ domain, *path = domain_url.split('/')
59
+ if domain =~ /\Awww\.(.*)\z/i
60
+ domain = $1
61
+ end
62
+
63
+ domain.downcase!
64
+
65
+ @domain_index[domain] ||= []
66
+ if !path.empty?
67
+ @domain_index[domain] << ['/' + path.join('/'), name_key]
68
+ else
69
+ @domain_index[domain] << ['/', name_key]
70
+ end
71
+ end
72
+ end
73
+
74
+ # Prune duplicate entries and sort with the most specific path first if there is more than one entry
75
+ # In this case, sorting by the longest string works fine
76
+ def optimize_index!
77
+ @domain_index.each do |key, val|
78
+ # Sort each path/name_key pair by the longest path
79
+ @domain_index[key].sort! { |a, b|
80
+ b[0].size <=> a[0].size
81
+ }.uniq!
82
+ end
83
+ end
84
+
85
+ # Given a string or URI, return a hash of data
86
+ def parse(obj)
87
+ url = obj.is_a?(URI) ? obj : URI.parse(obj.to_s)
88
+
89
+ if !['http', 'https'].include?(url.scheme)
90
+ raise InvalidUriError.new("Only HTTP and HTTPS schemes are supported -- #{url.scheme}")
91
+ end
92
+
93
+ data = { :known => false, :uri => url.to_s }
94
+
95
+ domain, name_key = domain_and_name_key_for(url)
96
+ if domain and name_key
97
+ referer_data = @name_hash[name_key]
98
+ data[:known] = true
99
+ data[:source] = referer_data[:source]
100
+ data[:medium] = referer_data[:medium]
101
+ data[:domain] = domain
102
+
103
+ # Parse parameters if the referer uses them
104
+ if url.query and referer_data[:parameters]
105
+ query_params = CGI.parse(url.query)
106
+ referer_data[:parameters].each do |param|
107
+ # If there is a matching parameter, get the first non-blank value
108
+ if !(values = query_params[param]).empty?
109
+ data[:term] = values.select { |v| v.strip != "" }.first
110
+ break if data[:term]
111
+ end
112
+ end
113
+ end
114
+ end
115
+
116
+ data
117
+ rescue URI::InvalidURIError
118
+ raise InvalidUriError.new("Unable to parse URI, not a URI? -- #{obj.inspect}", $!)
119
+ end
120
+
121
+ protected
122
+
123
+ # Determine the correct name_key for this host and path
124
+ def domain_and_name_key_for(uri)
125
+ # Create a proc that will return immediately
126
+ check = Proc.new do |domain|
127
+ domain.downcase!
128
+ if paths = @domain_index[domain]
129
+ paths.each do |path, name_key|
130
+ return [domain, name_key] if uri.path.include?(path)
131
+ end
132
+ end
133
+ end
134
+
135
+ # First check hosts with and without the www prefix with the path
136
+ if uri.host =~ /\Awww\.(.+)\z/i
137
+ check.call $1
138
+ else
139
+ check.call uri.host
140
+ end
141
+
142
+ # Remove subdomains until only three are left (probably good enough)
143
+ host_arr = uri.host.split(".")
144
+ while host_arr.size > 2 do
145
+ host_arr.shift
146
+ check.call host_arr.join(".")
147
+ end
148
+
149
+ nil
150
+ end
151
+
152
+ def deserialize_referer_data(data, ext)
153
+ # Parse the loaded data with the correct parser
154
+ deserialized_data = if ['.yml', '.yaml'].include?(ext)
155
+ deserialize_yaml(data)
156
+ elsif ext == '.json'
157
+ deserialize_json(data)
158
+ else
159
+ raise UnsupportedFormatError.new("Only yaml and json file formats are currently supported -- #{@msg}")
160
+ end
161
+
162
+ begin
163
+ parse_referer_data deserialized_data
164
+ rescue
165
+ raise CorruptReferersError.new("Unable to parse data file -- #{$!.class} #{$!.to_s}", $!)
166
+ end
167
+ end
168
+
169
+ def deserialize_yaml(data)
170
+ require 'yaml'
171
+ YAML.load(data)
172
+ rescue Exception => e
173
+ raise CorruptReferersError.new("Unable to YAML file -- #{e.to_s}", e)
174
+ end
175
+
176
+ def deserialize_json(data)
177
+ require 'json'
178
+ JSON.parse(data)
179
+ rescue JSON::ParserError
180
+ raise CorruptReferersError.new("Unable to JSON file -- #{$!.to_s}", $!)
181
+ end
182
+
183
+ def read_referer_data(uri)
184
+ # Attempt to read the data from the network if application, or the file on the local system
185
+ if uri =~ /\A(?:ht|f)tps?:\/\//
186
+ require 'open-uri'
187
+ begin
188
+ open(uri).read
189
+ rescue OpenURI::HTTPError
190
+ raise InvalidUriError.new("Cannot load referer data from URI #{uri} -- #{$!.to_s}", $!)
191
+ end
192
+ else
193
+ File.read(uri)
194
+ end
195
+ end
196
+
197
+ # Create an index that maps domains/paths to their name/medium and a hash that contains their metadata
198
+ # The index strips leading www in order to keep the index smaller
199
+ # Format of the domain_index:
200
+ # { domain => [[path1, name_key], [path2, name_key], ... ] }
201
+ # Format of the name_hash:
202
+ # { name_key => {:source, :medium, :parameters} }
203
+ def parse_referer_data(data)
204
+ data.each do |medium, name_hash|
205
+ name_hash.each do |name, name_data|
206
+ add_referer(medium, name, name_data['domains'], name_data['parameters'])
207
+ end
208
+ end
209
+
210
+ optimize_index!
211
+ rescue
212
+ raise CorruptReferersError.new("Unable to parse referer data", $!)
213
+ end
214
+ end
215
+ end
@@ -0,0 +1,19 @@
1
+ # Copyright (c) 2012-2013 Snowplow Analytics Ltd. All rights reserved.
2
+ #
3
+ # This program is licensed to you under the Apache License Version 2.0,
4
+ # and you may not use this file except in compliance with the Apache License Version 2.0.
5
+ # You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
6
+ #
7
+ # Unless required by applicable law or agreed to in writing,
8
+ # software distributed under the Apache License Version 2.0 is distributed on an
9
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
11
+
12
+ # Original Author:: Yali Sassoon (mailto:support@snowplowanalytics.com)
13
+ # Copyright:: Copyright (c) 2012-2013 Snowplow Analytics Ltd
14
+ # License:: Apache License Version 2.0
15
+
16
+ module RefererParser
17
+ NAME = "jobs-referer-parser"
18
+ VERSION = "0.0.1"
19
+ end
@@ -0,0 +1,21 @@
1
+ # Copyright (c) 2012-2013 Snowplow Analytics Ltd. All rights reserved.
2
+ #
3
+ # This program is licensed to you under the Apache License Version 2.0,
4
+ # and you may not use this file except in compliance with the Apache License Version 2.0.
5
+ # You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
6
+ #
7
+ # Unless required by applicable law or agreed to in writing,
8
+ # software distributed under the Apache License Version 2.0 is distributed on an
9
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
11
+
12
+ # Author:: Yali Sassoon (mailto:support@snowplowanalytics.com)
13
+ # Copyright:: Copyright (c) 2012-2013 Snowplow Analytics Ltd
14
+ # License:: Apache License Version 2.0
15
+
16
+ require "referer-parser/version"
17
+ require "referer-parser/errors"
18
+ require "referer-parser/parser"
19
+
20
+ module RefererParser
21
+ end
@@ -0,0 +1,38 @@
1
+ # Copyright (c) 2012-2013 Snowplow Analytics Ltd. All rights reserved.
2
+ #
3
+ # This program is licensed to you under the Apache License Version 2.0,
4
+ # and you may not use this file except in compliance with the Apache License Version 2.0.
5
+ # You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
6
+ #
7
+ # Unless required by applicable law or agreed to in writing,
8
+ # software distributed under the Apache License Version 2.0 is distributed on an
9
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ # See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
11
+
12
+ # Author:: Yali Sassoon (mailto:support@snowplowanalytics.com)
13
+ # Copyright:: Copyright (c) 2012-2013 Snowplow Analytics Ltd
14
+ # License:: Apache License Version 2.0
15
+
16
+ # -*- encoding: utf-8 -*-
17
+ lib = File.expand_path('../lib', __FILE__)
18
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
19
+ require 'referer-parser/version'
20
+
21
+ Gem::Specification.new do |gem|
22
+ gem.authors = ["Yali Sassoon", "Martin Loy", "Alex Dean", "Kelley Reynolds", "Shiv Bharthur"]
23
+ gem.email = ["shiv@recroup.com"]
24
+ gem.description = %q{Library for extracting marketing attribution data from referer URLs}
25
+ gem.summary = %q{Library for extracting marketing attribution data (e.g. search terms) from referer (sic) URLs. This is used by Recroup (http://github.com/bharthur/jobs-referer-parser). Originally developed by Snowplow (http://github.com/snowplow/snowplow).}
26
+ gem.homepage = "http://github.com/bharthur/jobs-referer-parser"
27
+
28
+ gem.files = `git ls-files`.split($/)
29
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
30
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
31
+ gem.name = RefererParser::NAME
32
+ gem.version = RefererParser::VERSION
33
+ gem.platform = Gem::Platform::RUBY
34
+ gem.require_paths = ["lib"]
35
+
36
+ gem.add_development_dependency "rspec", "~> 2.6"
37
+ gem.add_development_dependency "rake", ">= 0.9.2"
38
+ end
@@ -0,0 +1,9 @@
1
+ {
2
+ "internal": {
3
+ "SnowPlow": {
4
+ "domains": [
5
+ "www.snowplowanalytics.com"
6
+ ]
7
+ }
8
+ }
9
+ }
@@ -0,0 +1 @@
1
+ This has the right extension but is unparsable gibberish to json:{}}}}
@@ -0,0 +1,2 @@
1
+ this:is invalid:yaml:
2
+ !!!
@@ -0,0 +1,234 @@
1
+ [
2
+ {
3
+ "spec": "Google Images search",
4
+ "uri": "http://www.google.fr/imgres?q=Ogham+the+celtic+oracle&hl=fr&safe=off&client=firefox-a&hs=ZDu&sa=X&rls=org.mozilla:fr-FR:unofficial&tbm=isch&prmd=imvnsa&tbnid=HUVaj-o88ZRdYM:&imgrefurl=http://www.psychicbazaar.com/oracles/101-ogham-the-celtic-oracle-set.html&docid=DY5_pPFMliYUQM&imgurl=http://mdm.pbzstatic.com/oracles/ogham-the-celtic-oracle-set/montage.png&w=734&h=250&ei=GPdWUIePCOqK0AWp3oCQBA&zoom=1&iact=hc&vpx=129&vpy=276&dur=827&hovh=131&hovw=385&tx=204&ty=71&sig=104115776612919232039&page=1&tbnh=69&tbnw=202&start=0&ndsp=26&ved=1t:429,r:13,s:0,i:114&biw=1272&bih=826",
5
+ "medium": "search",
6
+ "source": "Google Images",
7
+ "term": "Ogham the celtic oracle",
8
+ "known": true
9
+ },
10
+ {
11
+ "spec": "Yahoo! Images search",
12
+ "uri": "http://it.images.search.yahoo.com/images/view;_ylt=A0PDodgQmGBQpn4AWQgdDQx.;_ylu=X3oDMTBlMTQ4cGxyBHNlYwNzcgRzbGsDaW1n?back=http%3A%2F%2Fit.images.search.yahoo.com%2Fsearch%2Fimages%3Fp%3DEarth%2BMagic%2BOracle%2BCards%26fr%3Dmcafee%26fr2%3Dpiv-web%26tab%3Dorganic%26ri%3D5&w=1064&h=1551&imgurl=mdm.pbzstatic.com%2Foracles%2Fearth-magic-oracle-cards%2Fcard-1.png&rurl=http%3A%2F%2Fwww.psychicbazaar.com%2Foracles%2F143-earth-magic-oracle-cards.html&size=2.8+KB&name=Earth+Magic+Oracle+Cards+-+Psychic+Bazaar&p=Earth+Magic+Oracle+Cards&oid=f0a5ad5c4211efe1c07515f56cf5a78e&fr2=piv-web&fr=mcafee&tt=Earth%2BMagic%2BOracle%2BCards%2B-%2BPsychic%2BBazaar&b=0&ni=90&no=5&ts=&tab=organic&sigr=126n355ib&sigb=13hbudmkc&sigi=11ta8f0gd&.crumb=IZBOU1c0UHU",
13
+ "medium": "search",
14
+ "source": "Yahoo! Images",
15
+ "term": "Earth Magic Oracle Cards",
16
+ "known": true
17
+ },
18
+ {
19
+ "spec": "Powered by Google",
20
+ "uri": "http://isearch.avg.com/pages/images.aspx?q=tarot+card+change&sap=dsp&lang=en&mid=209215200c4147d1a9d6d1565005540b-b0d4f81a8999f5981f04537c5ec8468fd5234593&cid=%7B50F9298B-C111-4C7E-9740-363BF0015949%7D&v=12.1.0.21&ds=AVG&d=7%2F23%2F2012+10%3A31%3A08+PM&pr=fr&sba=06oENya4ZG1YS6vOLJwpLiFdjG91ICt2YE59W2p5ENc2c4w8KvJb5xbvjkj3ceMjnyTSpZq-e6pj7GQUylIQtuK4psJU60wZuI-8PbjX-OqtdX3eIcxbMoxg3qnIasP0ww2fuID1B-p2qJln8vBHxWztkpxeixjZPSppHnrb9fEcx62a9DOR0pZ-V-Kjhd-85bIL0QG5qi1OuA4M1eOP4i_NzJQVRXPQDmXb-CpIcruc2h5FE92Tc8QMUtNiTEWBbX-QiCoXlgbHLpJo5Jlq-zcOisOHNWU2RSHYJnK7IUe_SH6iQ.%2CYT0zO2s9MTA7aD1mNjZmZDBjMjVmZDAxMGU4&snd=hdr&tc=test1",
21
+ "medium": "search",
22
+ "source": "Google",
23
+ "term": "tarot card change",
24
+ "known": true
25
+ },
26
+ {
27
+ "spec": "Google search #1",
28
+ "uri": "http://www.google.com/search",
29
+ "medium": "search",
30
+ "source": "Google",
31
+ "term": null,
32
+ "known": true
33
+ },
34
+ {
35
+ "spec": "Google search #2",
36
+ "uri": "http://www.google.com/search?q=gateway+oracle+cards+denise+linn&hl=en&client=safari",
37
+ "medium": "search",
38
+ "source": "Google",
39
+ "term": "gateway oracle cards denise linn",
40
+ "known": true
41
+ },
42
+ {
43
+ "spec": "Yahoo! search",
44
+ "uri": "http://es.search.yahoo.com/search;_ylt=A7x9QbwbZXxQ9EMAPCKT.Qt.?p=BIEDERMEIER+FORTUNE+TELLING+CARDS&ei=utf-8&type=685749&fr=chr-greentree_gc&xargs=0&pstart=1&b=11",
45
+ "medium": "search",
46
+ "source": "Yahoo!",
47
+ "term": "BIEDERMEIER FORTUNE TELLING CARDS",
48
+ "known": true
49
+ },
50
+ {
51
+ "spec": "PriceRunner search",
52
+ "uri": "http://www.pricerunner.co.uk/search?displayNoHitsMessage=1&q=wild+wisdom+of+the+faery+oracle",
53
+ "medium": "search",
54
+ "source": "PriceRunner",
55
+ "term": "wild wisdom of the faery oracle",
56
+ "known": true
57
+ },
58
+ {
59
+ "spec": "Bing Images search",
60
+ "uri": "http://www.bing.com/images/search?q=psychic+oracle+cards&view=detail&id=D268EDDEA8D3BF20AF887E62AF41E8518FE96F08",
61
+ "medium": "search",
62
+ "source": "Bing Images",
63
+ "term": "psychic oracle cards",
64
+ "known": true
65
+ },
66
+ {
67
+ "spec": "IXquick search",
68
+ "uri": "https://s3-us3.ixquick.com/do/search",
69
+ "medium": "search",
70
+ "source": "IXquick",
71
+ "term": null,
72
+ "known": true
73
+ },
74
+ {
75
+ "spec": "AOL search",
76
+ "uri": "http://aolsearch.aol.co.uk/aol/search?s_chn=hp&enabled_terms=&s_it=aoluk-homePage50&q=pendulums",
77
+ "medium": "search",
78
+ "source": "AOL",
79
+ "term": "pendulums",
80
+ "known": true
81
+ },
82
+ {
83
+ "spec": "AOL search.com",
84
+ "uri": "http://www.aolsearch.com/search?s_pt=hp&s_gl=NL&query=voorbeeld+cv+competenties&invocationType=tb50hpcnnbie7-nl-nl",
85
+ "medium": "search",
86
+ "source": "AOL",
87
+ "term": "voorbeeld cv competenties",
88
+ "known": true
89
+ },
90
+ {
91
+ "spec": "Ask search",
92
+ "uri": "http://uk.search-results.com/web?qsrc=1&o=1921&l=dis&q=pendulums&dm=ctry&atb=sysid%3D406%3Aappid%3D113%3Auid%3D8f40f651e7b608b5%3Auc%3D1346336505%3Aqu%3Dpendulums%3Asrc%3Dcrt%3Ao%3D1921&locale=en_GB",
93
+ "medium": "search",
94
+ "source": "Ask",
95
+ "term": "pendulums",
96
+ "known": true
97
+ },
98
+ {
99
+ "spec": "Mail.ru search",
100
+ "uri": "http://go.mail.ru/search?q=Gothic%20Tarot%20Cards&where=any&num=10&rch=e&sf=20",
101
+ "medium": "search",
102
+ "source": "Mail.ru",
103
+ "term": "Gothic Tarot Cards",
104
+ "known": true
105
+ },
106
+ {
107
+ "spec": "Yandex search",
108
+ "uri": "http://images.yandex.ru/yandsearch?text=Blue%20Angel%20Oracle%20Blue%20Angel%20Oracle&noreask=1&pos=16&rpt=simage&lr=45&img_url=http%3A%2F%2Fmdm.pbzstatic.com%2Foracles%2Fblue-angel-oracle%2Fbox-small.png",
109
+ "medium": "search",
110
+ "source": "Yandex Images",
111
+ "term": "Blue Angel Oracle Blue Angel Oracle",
112
+ "known": true
113
+ },
114
+ {
115
+ "spec": "Ask toolbar search",
116
+ "uri": "http://search.tb.ask.com/search/GGmain.jhtml?cb=AYY&pg=GGmain&p2=%5EAYY%5Exdm071%5EYYA%5Eid&n=77fdaa55&qid=c2678d9147654034bb8b16daa7bfb48c&ss=sub&st=hp&ptb=F9FC6C22-EAE6-4D1E-8126-A70119B6E02F&si=flvrunner&tpr=hst&searchfor=CARA+MEMASAK+CUMI+CUMI&ots=1219016089614",
117
+ "medium": "search",
118
+ "source": "Ask Toolbar",
119
+ "term": "CARA MEMASAK CUMI CUMI",
120
+ "known": true
121
+ },
122
+ {
123
+ "spec": "Ask toolbar search #2",
124
+ "uri": "http://search.tb.ask.com/search/GGmain.jhtml?&st=hp&p2=%5EZU%5Exdm458%5EYYA%5Eus&n=77fda1bd&ptb=F0B68CA5-4791-4376-BFCC-5F0100329FB6&si=CMKg9-nX07oCFSjZQgodcikACQ&tpr=hpsbsug&searchfor=test",
125
+ "medium": "search",
126
+ "source": "Ask Toolbar",
127
+ "term": "test",
128
+ "known": true
129
+ },
130
+ {
131
+ "spec": "Voila search",
132
+ "uri": "http://search.ke.voila.fr/?module=voila&bhv=web_fr&kw=test",
133
+ "medium": "search",
134
+ "source": "Voila",
135
+ "term": "test",
136
+ "known": true
137
+ },
138
+ {
139
+ "spec": "Dale search",
140
+ "uri": "http://www.dalesearch.com/?q=+lego.nl+%2Fclub&s=web&as=0&rlz=0&babsrc=HP_ss",
141
+ "medium": "search",
142
+ "source": "Dalesearch",
143
+ "term": " lego.nl /club",
144
+ "known": true
145
+ },
146
+ {
147
+ "spec": "Twitter redirect",
148
+ "uri": "http://t.co/chrgFZDb",
149
+ "medium": "social",
150
+ "source": "Twitter",
151
+ "term": null,
152
+ "known": true
153
+ },
154
+ {
155
+ "spec": "Facebook social",
156
+ "uri": "http://www.facebook.com/l.php?u=http%3A%2F%2Fwww.psychicbazaar.com&h=yAQHZtXxS&s=1",
157
+ "medium": "social",
158
+ "source": "Facebook",
159
+ "term": null,
160
+ "known": true
161
+ },
162
+ {
163
+ "spec": "Facebook mobile",
164
+ "uri": "http://m.facebook.com/l.php?u=http%3A%2F%2Fwww.psychicbazaar.com%2Fblog%2F2012%2F09%2Fpsychic-bazaar-reviews-tarot-foundations-31-days-to-read-tarot-with-confidence%2F&h=kAQGXKbf9&s=1",
165
+ "medium": "social",
166
+ "source": "Facebook",
167
+ "term": null,
168
+ "known": true
169
+ },
170
+ {
171
+ "spec": "Odnoklassniki",
172
+ "uri": "http://www.odnoklassniki.ru/dk?cmd=logExternal&st._aid=Conversations_Openlink&st.name=externalLinkRedirect&st.link=http%3A%2F%2Fwww.psychicbazaar.com%2Foracles%2F187-blue-angel-oracle.html",
173
+ "medium": "social",
174
+ "source": "Odnoklassniki",
175
+ "term": null,
176
+ "known": true
177
+ },
178
+ {
179
+ "spec": "Tumblr social #1",
180
+ "uri": "http://www.tumblr.com/dashboard",
181
+ "medium": "social",
182
+ "source": "Tumblr",
183
+ "term": null,
184
+ "known": true
185
+ },
186
+ {
187
+ "spec": "Tumblr w subdomain",
188
+ "uri": "http://psychicbazaar.tumblr.com/",
189
+ "medium": "social",
190
+ "source": "Tumblr",
191
+ "term": null,
192
+ "known": true
193
+ },
194
+ {
195
+ "spec": "Yahoo! Mail",
196
+ "uri": "http://36ohk6dgmcd1n-c.c.yom.mail.yahoo.net/om/api/1.0/openmail.app.invoke/36ohk6dgmcd1n/11/1.0.35/us/en-US/view.html/0",
197
+ "medium": "email",
198
+ "source": "Yahoo! Mail",
199
+ "term": null,
200
+ "known": true
201
+ },
202
+ {
203
+ "spec": "Outlook.com mail",
204
+ "uri": "http://co106w.col106.mail.live.com/default.aspx?rru=inbox",
205
+ "medium": "email",
206
+ "source": "Outlook.com",
207
+ "term": null,
208
+ "known": true
209
+ },
210
+ {
211
+ "spec": "Orange Webmail",
212
+ "uri": "http://webmail1m.orange.fr/webmail/fr_FR/read.html?FOLDER=SF_INBOX&IDMSG=8594&check=&SORTBY=31",
213
+ "medium": "email",
214
+ "source": "Orange Webmail",
215
+ "term": null,
216
+ "known": true
217
+ },
218
+ {
219
+ "spec": "Internal HTTP",
220
+ "uri": "http://www.snowplowanalytics.com/about/team",
221
+ "medium": "internal",
222
+ "source": "SnowPlow",
223
+ "term": null,
224
+ "known": true
225
+ },
226
+ {
227
+ "spec": "Internal HTTPS",
228
+ "uri": "https://www.snowplowanalytics.com/account/profile",
229
+ "medium": "internal",
230
+ "source": "SnowPlow",
231
+ "term": null,
232
+ "known": true
233
+ }
234
+ ]