ndd-url_checker 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/.travis.yml +2 -1
  4. data/Gemfile.lock +57 -44
  5. data/README.md +5 -2
  6. data/VERSION +1 -1
  7. data/lib/ndd/url_checker.rb +2 -0
  8. data/lib/ndd/url_checker/blocking_url_checker.rb +7 -4
  9. data/lib/ndd/url_checker/forked_url_checker.rb +4 -2
  10. data/lib/ndd/url_checker/reporting_url_checker.csv.erb +2 -2
  11. data/lib/ndd/url_checker/reporting_url_checker.html.erb +171 -80
  12. data/lib/ndd/url_checker/reporting_url_checker.json.erb +16 -9
  13. data/lib/ndd/url_checker/reporting_url_checker.rb +22 -11
  14. data/lib/ndd/url_checker/status.rb +1 -1
  15. data/lib/ndd/url_checker/status_decorator.rb +64 -0
  16. data/ndd-url_checker.gemspec +6 -4
  17. data/spec/ndd/url_checker/abstract_url_checker_spec.rb +1 -1
  18. data/spec/ndd/url_checker/blocking_url_checker_spec.rb +1 -1
  19. data/spec/ndd/url_checker/forked_url_checker_spec.rb +1 -1
  20. data/spec/ndd/url_checker/parallel_url_checker_spec.rb +1 -1
  21. data/spec/ndd/url_checker/reporting_url_checker/custom.txt.erb +2 -2
  22. data/spec/ndd/url_checker/reporting_url_checker/multiple_urls.csv +5 -3
  23. data/spec/ndd/url_checker/reporting_url_checker/multiple_urls.html +227 -92
  24. data/spec/ndd/url_checker/reporting_url_checker/multiple_urls.json +29 -10
  25. data/spec/ndd/url_checker/reporting_url_checker/multiple_urls.txt +12 -2
  26. data/spec/ndd/url_checker/reporting_url_checker/single_url.csv +1 -1
  27. data/spec/ndd/url_checker/reporting_url_checker/single_url.html +163 -78
  28. data/spec/ndd/url_checker/reporting_url_checker/single_url.json +14 -7
  29. data/spec/ndd/url_checker/reporting_url_checker_spec.rb +29 -12
  30. data/spec/ndd/url_checker/status_decorator_spec.rb +208 -0
  31. data/spec/ndd/url_checker/status_spec.rb +10 -10
  32. data/spec/ndd/url_checker/threaded_url_checker_spec.rb +1 -1
  33. data/spec/spec_helper.rb +1 -3
  34. data/spec/support/multiple_url_checker_spec.rb +4 -4
  35. data/spec/support/single_url_checker_spec.rb +74 -21
  36. metadata +5 -3
@@ -1,20 +1,27 @@
1
1
  {
2
2
  "benchmark": {
3
- "utime": "<%= benchmark.utime %>",
4
- "stime": "<%= benchmark.stime %>",
5
- "total": "<%= benchmark.total %>",
6
- "real": "<%= benchmark.real %>",
7
- "size": "<%= results.size %>",
8
- "throughput": "<%= benchmark.real/results.size %>"
3
+ "total_duration": <%= benchmark.total_duration %>,
4
+ "average_duration": <%= benchmark.average_duration %>,
5
+ "average_throughput": <%= benchmark.average_throughput %>
6
+ },
7
+ "statistics": {
8
+ "count": <%= urls.count %>,
9
+ "valid_count": <%= urls.valid_count %>,
10
+ "direct_count": <%= urls.direct_count %>,
11
+ "redirected_count": <%= urls.redirected_count %>,
12
+ "invalid_count": <%= urls.invalid_count %>,
13
+ "failed_count": <%= urls.failed_count %>,
14
+ "too_many_redirects_count": <%= urls.too_many_redirects_count %>,
15
+ "unknown_host_count": <%= urls.unknown_host_count %>
9
16
  },
10
17
  "results": [
11
- <% results.each_with_index do |status, index| %>
18
+ <% statuses.each_with_index do |status, index| %>
12
19
  {
13
20
  "index": <%= index+1 %>,
14
21
  "url": "<%= status.uri %>",
15
22
  "code": "<%= status.code %>",
16
- "comment": "<% if status.invalid? %><%= status.error %><% end %>"
17
- }<% if index < results.size - 1 %>,<% end %>
23
+ "details": "<% if status.invalid? %><%= status.error %><% end %>"
24
+ }<% if index < statuses.size - 1 %>,<% end %>
18
25
  <% end %>
19
26
  ]
20
27
  }
@@ -24,22 +24,33 @@ module NDD
24
24
  def check(*urls)
25
25
  results = nil
26
26
  benchmark = Benchmark.measure { results = @delegate.check(*urls) }
27
- @logger.debug "Checking #{urls.size} URL(s) benchmark: #{benchmark}"
27
+ @logger.debug "Checked #{urls.size} URL(s) benchmark: #{benchmark}"
28
28
 
29
29
  if urls.size > 1
30
- @context = OpenStruct.new(
31
- {
32
- benchmark: benchmark,
33
- results: results.sort_by { |status| status.uri }
34
- })
30
+ statuses = results.map { |status| StatusDecorator.new(status) }.sort_by { |status| status.uri }
35
31
  else
36
- @context = OpenStruct.new(
37
- {
38
- benchmark: benchmark,
39
- results: [results]
40
- })
32
+ statuses = [results].map { |status| StatusDecorator.new(status) }
41
33
  end
42
34
 
35
+ @context = OpenStruct.new
36
+ @context.statuses = statuses
37
+
38
+ @context.urls = OpenStruct.new
39
+ @context.urls.count = urls.size
40
+ @context.urls.valid_count = statuses.select { |status| status.valid? }.size
41
+ @context.urls.direct_count = statuses.select { |status| status.code == :direct }.size
42
+ @context.urls.redirected_count = statuses.select { |status| status.code == :redirected }.size
43
+ @context.urls.invalid_count = statuses.select { |status| status.invalid? }.size
44
+ @context.urls.failed_count = statuses.select { |status| status.code == :failed }.size
45
+ @context.urls.too_many_redirects_count = statuses.select { |status| status.code == :too_many_redirects }.size
46
+ @context.urls.unknown_host_count = statuses.select { |status| status.code == :unknown_host }.size
47
+
48
+ @context.benchmark = OpenStruct.new
49
+ @context.benchmark.raw = benchmark
50
+ @context.benchmark.total_duration = benchmark.real
51
+ @context.benchmark.average_duration = benchmark.real / urls.size
52
+ @context.benchmark.average_throughput= urls.size / benchmark.real
53
+
43
54
  results
44
55
  end
45
56
 
@@ -49,7 +49,7 @@ module NDD
49
49
  end
50
50
 
51
51
  # When a generic error is raised.
52
- # @param error [StandardError|String] the generic error.
52
+ # @param error [StandardError] the generic error.
53
53
  # @return [self]
54
54
  def failed(error)
55
55
  @error = error
@@ -0,0 +1,64 @@
1
+ require 'delegate'
2
+
3
+ module NDD
4
+ module UrlChecker
5
+
6
+ # Decorate a [Status] for reporting.
7
+ # @author David DIDIER
8
+ class StatusDecorator < SimpleDelegator
9
+
10
+ def code_as_css
11
+ code.to_s.gsub(/_/, '-')
12
+ end
13
+
14
+ def details_title
15
+ case code
16
+ when :direct then
17
+ nil
18
+ when :redirected then
19
+ uris.size - 1
20
+ when :failed then
21
+ return nil unless error
22
+ return error.class.to_s
23
+ when :too_many_redirects then
24
+ uris.size - 1
25
+ when :unknown_host then
26
+ return uris.last
27
+ end
28
+ end
29
+
30
+ def details_body
31
+ case code
32
+ when :direct then
33
+ nil
34
+ when :redirected then
35
+ uris.map { |uri| "- #{uri}\n" }.join
36
+ when :failed then
37
+ return nil unless error
38
+ return error.body if error.kind_of?(Net::HTTPResponse)
39
+ return error.to_s
40
+ when :too_many_redirects then
41
+ uris.map { |uri| "- #{uri}\n" }.join
42
+ when :unknown_host then
43
+ uris.map { |uri| "- #{uri}\n" }.join
44
+ end
45
+ end
46
+
47
+ def details_body_as_html
48
+ body = <<-HTML.gsub(/^ +/, '')
49
+ <p><em>Status:</em> #{code}</p>
50
+ <p><em>URIs:</em><p>
51
+ <ol>#{uris.map { |uri| "<li>#{uri}</li>" }.join}</ol>
52
+ HTML
53
+
54
+ if error
55
+ body += "<p><em>Error:</em> #{error.class.to_s}</p>"
56
+ body += "<p><pre>#{error.body}</pre></p>" if error.kind_of?(Net::HTTPResponse)
57
+ end
58
+
59
+ body
60
+ end
61
+ end
62
+
63
+ end
64
+ end
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: ndd-url_checker 0.2.1 ruby lib
5
+ # stub: ndd-url_checker 0.3.0 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "ndd-url_checker"
9
- s.version = "0.2.1"
9
+ s.version = "0.3.0"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib"]
13
13
  s.authors = ["David DIDIER"]
14
- s.date = "2014-12-15"
14
+ s.date = "2015-06-09"
15
15
  s.description = "Validate URLs"
16
16
  s.email = "c_inconnu2@yahoo.fr"
17
17
  s.extra_rdoc_files = [
@@ -42,6 +42,7 @@ Gem::Specification.new do |s|
42
42
  "lib/ndd/url_checker/reporting_url_checker.json.erb",
43
43
  "lib/ndd/url_checker/reporting_url_checker.rb",
44
44
  "lib/ndd/url_checker/status.rb",
45
+ "lib/ndd/url_checker/status_decorator.rb",
45
46
  "lib/ndd/url_checker/threaded_url_checker.rb",
46
47
  "ndd-url_checker.gemspec",
47
48
  "spec/ndd/url_checker/abstract_url_checker_spec.rb",
@@ -58,6 +59,7 @@ Gem::Specification.new do |s|
58
59
  "spec/ndd/url_checker/reporting_url_checker/single_url.json",
59
60
  "spec/ndd/url_checker/reporting_url_checker/single_url.txt",
60
61
  "spec/ndd/url_checker/reporting_url_checker_spec.rb",
62
+ "spec/ndd/url_checker/status_decorator_spec.rb",
61
63
  "spec/ndd/url_checker/status_spec.rb",
62
64
  "spec/ndd/url_checker/threaded_url_checker_spec.rb",
63
65
  "spec/spec_helper.rb",
@@ -66,7 +68,7 @@ Gem::Specification.new do |s|
66
68
  ]
67
69
  s.homepage = "http://github.com/ddidier/ndd-url_checker"
68
70
  s.licenses = ["MIT"]
69
- s.rubygems_version = "2.4.4"
71
+ s.rubygems_version = "2.4.8"
70
72
  s.summary = "Validate URLs"
71
73
 
72
74
  if s.respond_to? :specification_version then
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe NDD::UrlChecker::AbstractUrlChecker do
3
+ RSpec.describe NDD::UrlChecker::AbstractUrlChecker do
4
4
 
5
5
  context '#check' do
6
6
  it 'is not implemented' do
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe NDD::UrlChecker::BlockingUrlChecker do
3
+ RSpec.describe NDD::UrlChecker::BlockingUrlChecker do
4
4
 
5
5
  before(:all) do
6
6
  # Logging.logger.root.level = :debug
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe NDD::UrlChecker::ForkedUrlChecker do
3
+ RSpec.describe NDD::UrlChecker::ForkedUrlChecker do
4
4
 
5
5
  before(:all) do
6
6
  # Logging.logger.root.level = :debug
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe NDD::UrlChecker::ParallelUrlChecker do
3
+ RSpec.describe NDD::UrlChecker::ParallelUrlChecker do
4
4
 
5
5
  before(:all) do
6
6
  # Logging.logger.root.level = :debug
@@ -1,6 +1,6 @@
1
- count = <%= results.size %>
1
+ count = <%= statuses.size %>
2
2
 
3
- <% results.each_with_index do |status, index| %>
3
+ <% statuses.each_with_index do |status, index| %>
4
4
  - index = <%= index+1 %>
5
5
  - uri = <%= status.uri %>
6
6
  - valid = <%= status.valid? %>
@@ -1,4 +1,6 @@
1
- Index,URL,Result,Code,Comment
2
- 1,http://www.google.com,valid,direct,
1
+ Index,URL,Result,Code,Details
2
+ 1,http://www.google.com,valid,redirected,
3
3
  2,http://www.google.de,invalid,failed,some error
4
- 3,http://www.google.fr,valid,direct,
4
+ 3,http://www.google.es,invalid,too_many_redirects,
5
+ 4,http://www.google.fr,valid,direct,
6
+ 5,http://www.google.it,invalid,unknown_host,
@@ -2,110 +2,245 @@
2
2
  <html lang="en">
3
3
 
4
4
  <head>
5
- <meta charset="UTF-8">
6
- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
7
- <style>
8
- body {
9
- padding: 1em;
5
+ <meta charset="UTF-8" />
6
+
7
+ <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />
8
+ <style type="text/css">
9
+ .popover-title {
10
+ font-weight: bold;
11
+ }
12
+
13
+ .popover-content em {
14
+ font-style: normal;
15
+ font-weight: bold;
16
+ }
17
+
18
+ .popover-content ol {
19
+ margin-left: -20px;
10
20
  }
11
21
  </style>
12
22
 
13
- <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
14
- <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
23
+ <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
24
+ <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
15
25
  <script language="JavaScript">
16
- $(document).ready(function() {
17
- $('input[type=radio][name=urlsFilter]').change(function() {
18
- if (this.value == 'all') {
19
- $('tr').show();
20
- }
21
- else if (this.value == 'invalid') {
22
- $('tr').not('.danger').hide();
23
- }
26
+ if (!window.ndd_url_checker) {
27
+ window.ndd_url_checker = {};
28
+ }
29
+
30
+ ndd_url_checker.STATES = ['direct', 'redirected', 'failed', 'too-many-redirects', 'unknown-host'];
31
+
32
+ ndd_url_checker.displayStates = function () {
33
+ var displayStates = {};
34
+ $.each(ndd_url_checker.STATES, function (_, state) {
35
+ var checked = $('.display-' + state).is(':checked');
36
+ displayStates[state] = checked;
37
+ });
38
+ return displayStates;
39
+ }
40
+
41
+ ndd_url_checker.filter = function () {
42
+ var displayStates = ndd_url_checker.displayStates();
43
+
44
+ $.each(displayStates, function (state, display) {
45
+ $('.result-' + state).toggle(display);
24
46
  });
47
+ }
48
+
49
+ $(document).ready(function () {
50
+ // show or hide results depending on their state
51
+ $.each(ndd_url_checker.STATES, function (_, state) {
52
+ $('.display-' + state).change(function () {
53
+ ndd_url_checker.filter();
54
+ });
55
+ });
56
+
57
+ // activate all tooltips
58
+ $('[data-toggle="popover"]')
59
+ .popover()
60
+ .click(function (e) {
61
+ e.preventDefault();
62
+ });
25
63
  });
26
64
  </script>
27
65
  </head>
28
66
 
67
+
29
68
  <body>
30
69
 
31
- <h1>URL Checker Report</h1>
32
-
33
- <table class="table table-condensed table-hover" style="width: auto">
34
- <tbody>
35
- <tr>
36
- <td>User CPU time</td>
37
- <td>XXX second(s)</td>
38
- </tr>
39
- <tr>
40
- <td>System CPU time</td>
41
- <td>XXX second(s)</td>
42
- </tr>
43
- <tr>
44
- <td>Total time</td>
45
- <td>XXX second(s)</td>
46
- </tr>
47
- <tr>
48
- <td>Elapsed real time</td>
49
- <td>XXX second(s)</td>
50
- </tr>
51
- <tr>
52
- <td>Number of URLs</td>
53
- <td>3</td>
54
- </tr>
55
- <tr>
56
- <td>Average time for 1 URL</td>
57
- <td>XXX second(s)</td>
58
- </tr>
59
- </tbody>
60
- </table>
61
-
62
- <div class="radio">
63
- <label>
64
- <input type="radio" name="urlsFilter" id="showAllUrls" value="all" checked="true" />
65
- Show all URLs
66
- </label>
67
- </div>
68
- <div class="radio">
69
- <label>
70
- <input type="radio" name="urlsFilter" id="showInvalidUrls" value="invalid" />
71
- Show invalid URLs
72
- </label>
73
- </div>
70
+ <div class="container">
71
+
72
+ <div class="page-header">
73
+ <h1>
74
+ <span class="glyphicon glyphicon-list-alt" aria-hidden="true"></span>
75
+ URL Checker Report
76
+ </h1>
77
+ </div>
78
+
79
+
80
+ <div class="row">
81
+ <div class="col-md-4">
82
+ <dl class="page-info dl-horizontal">
83
+ <dt>Number of URLs</dt>
84
+ <dd>5</dd>
85
+ <dt>Duration</dt>
86
+ <dd>123.456 s</dd>
87
+ <dt>Average duration</dt>
88
+ <dd>123.456 s/URL</dd>
89
+ <dt>Average throughput</dt>
90
+ <dd>123.456 URL/s</dd>
91
+ </dl>
92
+ </div>
93
+ <div class="col-md-4">
94
+ <dl class="page-info dl-horizontal">
95
+ <dt>Valid URLS</dt>
96
+ <dd>2</dd>
97
+ <dt>direct</dt>
98
+ <dd>1</dd>
99
+ <dt>redirected</dt>
100
+ <dd>1</dd>
101
+ </dl>
102
+ </div>
103
+ <div class="col-md-4">
104
+ <dl class="page-info dl-horizontal">
105
+ <dt>Invalid URLS</dt>
106
+ <dd>3</dd>
107
+ <dt>failed</dt>
108
+ <dd>1</dd>
109
+ <dt>too many redirects</dt>
110
+ <dd>1</dd>
111
+ <dt>unknown host</dt>
112
+ <dd>1</dd>
113
+ </dl>
114
+ </div>
115
+ </div>
116
+ <hr />
117
+
118
+
119
+ <div class="row page-controls hidden-print">
120
+ <div class="col-md-6">
121
+ <span>Valid URLs:</span>
122
+
123
+ <div class="btn-group page-display" data-toggle="buttons">
124
+ <label class="btn btn-default active">
125
+ <input type="checkbox" autocomplete="off" class="display-direct" checked="true" />
126
+ Direct (1)
127
+ </label>
128
+ <label class="btn btn-default active">
129
+ <input type="checkbox" autocomplete="off" class="display-redirected" checked="true" />
130
+ Redirected (1)
131
+ </label>
132
+ </div>
133
+ </div>
134
+ <div class="col-md-6">
135
+ <span>Invalid URLs:</span>
136
+
137
+ <div class="btn-group page-display" data-toggle="buttons">
138
+ <label class="btn btn-default active">
139
+ <input type="checkbox" autocomplete="off" class="display-failed" checked="true" />
140
+ Failed (1)
141
+ </label>
142
+ <label class="btn btn-default active">
143
+ <input type="checkbox" autocomplete="off" class="display-too-many-redirects" checked="true" />
144
+ Too many redirects (1)
145
+ </label>
146
+ <label class="btn btn-default active">
147
+ <input type="checkbox" autocomplete="off" class="display-unknown-host" checked="true" />
148
+ Unknown host (1)
149
+ </label>
150
+ </div>
151
+ </div>
152
+ </div>
153
+ <hr />
154
+
74
155
 
75
- <table class="table table-condensed table-hover" style="width: auto">
76
- <thead>
77
- <tr>
78
- <th>#</th>
79
- <th>URL</th>
80
- <th>Code</th>
81
- <th>Comment</th>
82
- </tr>
83
- </thead>
84
- <tbody>
85
-
86
- <tr class="">
87
- <td>1</td>
88
- <td><a href="http://www.google.com" target="_blank">http://www.google.com</a></td>
89
- <td>direct</td>
90
- <td></td>
91
- </tr>
92
-
93
- <tr class="danger">
94
- <td>2</td>
95
- <td><a href="http://www.google.de" target="_blank">http://www.google.de</a></td>
96
- <td>failed</td>
97
- <td>some error</td>
98
- </tr>
99
-
100
- <tr class="">
101
- <td>3</td>
102
- <td><a href="http://www.google.fr" target="_blank">http://www.google.fr</a></td>
103
- <td>direct</td>
104
- <td></td>
105
- </tr>
106
-
107
- </tbody>
108
- </table>
156
+ <table id="results" class="table table-condensed table-hover">
157
+ <thead>
158
+ <tr>
159
+ <th>#</th>
160
+ <th>URL</th>
161
+ <th>Code</th>
162
+ <th>Details</th>
163
+ </tr>
164
+ </thead>
165
+ <tbody>
166
+
167
+ <tr class="result result-redirected ">
168
+ <td>1</td>
169
+ <td><a href="http://www.google.com" target="_blank">http://www.google.com</a></td>
170
+ <td>redirected</td>
171
+ <td>1</td>
172
+ <td>
173
+ <a href="#" data-toggle="popover" data-placement="left" data-trigger="focus"
174
+ data-html="true" title="http://www.google.com" data-content="<p><em>Status:</em> redirected</p>
175
+ <p><em>URIs:</em><p>
176
+ <ol><li>http://www.google.com</li><li>http://www.google.fr</li></ol>
177
+ ">
178
+ <span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span>
179
+ </a>
180
+ </td>
181
+ </tr>
182
+
183
+ <tr class="result result-failed danger">
184
+ <td>2</td>
185
+ <td><a href="http://www.google.de" target="_blank">http://www.google.de</a></td>
186
+ <td>failed</td>
187
+ <td>StandardError</td>
188
+ <td>
189
+ <a href="#" data-toggle="popover" data-placement="left" data-trigger="focus"
190
+ data-html="true" title="http://www.google.de" data-content="<p><em>Status:</em> failed</p>
191
+ <p><em>URIs:</em><p>
192
+ <ol><li>http://www.google.de</li></ol>
193
+ <p><em>Error:</em> StandardError</p>">
194
+ <span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span>
195
+ </a>
196
+ </td>
197
+ </tr>
198
+
199
+ <tr class="result result-too-many-redirects danger">
200
+ <td>3</td>
201
+ <td><a href="http://www.google.es" target="_blank">http://www.google.es</a></td>
202
+ <td>too_many_redirects</td>
203
+ <td>1</td>
204
+ <td>
205
+ <a href="#" data-toggle="popover" data-placement="left" data-trigger="focus"
206
+ data-html="true" title="http://www.google.es" data-content="<p><em>Status:</em> too_many_redirects</p>
207
+ <p><em>URIs:</em><p>
208
+ <ol><li>http://www.google.es</li><li>http://www.google.fr</li></ol>
209
+ ">
210
+ <span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span>
211
+ </a>
212
+ </td>
213
+ </tr>
214
+
215
+ <tr class="result result-direct ">
216
+ <td>4</td>
217
+ <td><a href="http://www.google.fr" target="_blank">http://www.google.fr</a></td>
218
+ <td>direct</td>
219
+ <td></td>
220
+ <td>
221
+ </td>
222
+ </tr>
223
+
224
+ <tr class="result result-unknown-host danger">
225
+ <td>5</td>
226
+ <td><a href="http://www.google.it" target="_blank">http://www.google.it</a></td>
227
+ <td>unknown_host</td>
228
+ <td>http://www.google.it</td>
229
+ <td>
230
+ <a href="#" data-toggle="popover" data-placement="left" data-trigger="focus"
231
+ data-html="true" title="http://www.google.it" data-content="<p><em>Status:</em> unknown_host</p>
232
+ <p><em>URIs:</em><p>
233
+ <ol><li>http://www.google.it</li></ol>
234
+ ">
235
+ <span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span>
236
+ </a>
237
+ </td>
238
+ </tr>
239
+
240
+ </tbody>
241
+ </table>
242
+
243
+ </div>
109
244
 
110
245
  </body>
111
246
  </html>