Spy-Vs-Spy 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. data/Change.log +3 -0
  2. data/LICENSE +19 -0
  3. data/README +18 -0
  4. data/Rakefile +30 -0
  5. data/VERSION +1 -0
  6. data/lib/spy_vs_spy.rb +438 -0
  7. data/test/firefox/Firefox-3.1b2.txt +9 -0
  8. data/test/firefox/Firefox-3.1b2pre.txt +4 -0
  9. data/test/firefox/Firefox-3.1b3.txt +32 -0
  10. data/test/firefox/Firefox-3.1b3pre.txt +2 -0
  11. data/test/firefox/Firefox-3.5.1.txt +41 -0
  12. data/test/firefox/Firefox-3.5.12.txt +1 -0
  13. data/test/firefox/Firefox-3.5.2.txt +27 -0
  14. data/test/firefox/Firefox-3.5.3.txt +22 -0
  15. data/test/firefox/Firefox-3.5.3pre.txt +1 -0
  16. data/test/firefox/Firefox-3.5.4.txt +3 -0
  17. data/test/firefox/Firefox-3.5.5.txt +3 -0
  18. data/test/firefox/Firefox-3.5.txt +40 -0
  19. data/test/firefox/Firefox-3.5b4.txt +9 -0
  20. data/test/firefox/Firefox-3.5b4pre.txt +3 -0
  21. data/test/firefox/Firefox-3.6.txt +2 -0
  22. data/test/firefox/Firefox-3.6a1pre.txt +6 -0
  23. data/test/firefox/Firefox-3.6b1.txt +1 -0
  24. data/test/firefox/Firefox-3.8.txt +3 -0
  25. data/test/msie/MSIE-5.5.txt +177 -0
  26. data/test/msie/MSIE-5.5b1.txt +1 -0
  27. data/test/msie/MSIE-6,0.txt +1 -0
  28. data/test/msie/MSIE-6.0.1.txt +1 -0
  29. data/test/msie/MSIE-6.0.txt +1816 -0
  30. data/test/msie/MSIE-6.0b.txt +14 -0
  31. data/test/msie/MSIE-6.1.txt +2 -0
  32. data/test/msie/MSIE-7.0.txt +1208 -0
  33. data/test/msie/MSIE-7.0b.txt +12 -0
  34. data/test/msie/MSIE-8.0.txt +340 -0
  35. data/test/safari/Safari-1.0.3.txt +10 -0
  36. data/test/safari/Safari-1.0.txt +8 -0
  37. data/test/safari/Safari-1.2.2.txt +9 -0
  38. data/test/safari/Safari-1.2.3.txt +10 -0
  39. data/test/safari/Safari-1.2.4.txt +21 -0
  40. data/test/safari/Safari-1.2.txt +5 -0
  41. data/test/safari/Safari-1.3.1.txt +24 -0
  42. data/test/safari/Safari-1.3.2.txt +14 -0
  43. data/test/safari/Safari-1.3.txt +13 -0
  44. data/test/safari/Safari-2.0.1.txt +9 -0
  45. data/test/safari/Safari-2.0.2.txt +25 -0
  46. data/test/safari/Safari-2.0.3.txt +37 -0
  47. data/test/safari/Safari-2.0.4.txt +44 -0
  48. data/test/safari/Safari-2.0.txt +21 -0
  49. data/test/safari/Safari-3.0.1.txt +8 -0
  50. data/test/safari/Safari-3.0.2.txt +14 -0
  51. data/test/safari/Safari-3.0.3.txt +20 -0
  52. data/test/safari/Safari-3.0.4.txt +37 -0
  53. data/test/safari/Safari-3.0.txt +53 -0
  54. data/test/safari/Safari-3.1.1.txt +77 -0
  55. data/test/safari/Safari-3.1.2.txt +48 -0
  56. data/test/safari/Safari-3.1.txt +22 -0
  57. data/test/safari/Safari-3.2.1.txt +37 -0
  58. data/test/safari/Safari-3.2.2.txt +9 -0
  59. data/test/safari/Safari-3.2.3.txt +2 -0
  60. data/test/safari/Safari-3.2.txt +7 -0
  61. data/test/safari/Safari-4.0.1.txt +2 -0
  62. data/test/safari/Safari-4.0.2.txt +12 -0
  63. data/test/safari/Safari-4.0.3.txt +5 -0
  64. data/test/safari/Safari-4.0.txt +66 -0
  65. data/test/safari/Safari-4.0dp1.txt +8 -0
  66. data/test/safari/safari.txt +30 -0
  67. data/test/ss-test.rb +33 -0
  68. metadata +122 -0
@@ -0,0 +1,3 @@
1
+ Nov.19-2009:
2
+ -- corrected an error in the middleware that prevented it from working
3
+
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2009 Kristan 'Krispy' Uccello <krispy@soldierofcode.com> - Soldier Of Code
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,18 @@
1
+ =Spy vs Spy
2
+
3
+ == Intelligent User Agent parsing for the future! Now in Black & White
4
+
5
+ This is user agent parsing with lots and lots of tests. And accurate results. Its awesome
6
+
7
+ == Usage
8
+
9
+ >> require 'spy-vs-spy'
10
+ >> agent = SOC::SpyVsSpy.new("Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)")
11
+ << #<SoldierOfCode::SpyVsSpy:0x100351a28 @version.major="5", @agent="Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)", @identifier="", @product_token="Mozilla/4.0 ", @mobile=["iPhone", "iPod", "BlackBerry", "Android", "HTC-", "LG", "Motorola", "Nokia", "Treo", "Pre/", "Samsung", "SonyEricsson"], @renderer="", @browser="MSIE", @engine="", @version.minor="5", @ostype="Windows", @platform="Desktop", @detail="(compatible; MSIE 5.5; Windows NT 5.1; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)">
12
+ >> agent.browser
13
+ << "MSIE"
14
+ >> agent.version.to_s
15
+ << "5.5"
16
+ >> agent.version.major
17
+ >> "5"
18
+
@@ -0,0 +1,30 @@
1
+ require 'rake/testtask'
2
+
3
+ begin
4
+ require 'jeweler'
5
+ Jeweler::Tasks.new do |s|
6
+ s.name = "Spy-Vs-Spy"
7
+ s.description = s.summary = "Rack middleware to detect and provide more detail on the requesting user agent edit"
8
+ s.email = "kuccello@gmail.com"
9
+ s.homepage = "http://github.com/kuccello/Spy-Vs-Spy"
10
+ s.authors = ['Kristan "Krispy" Uccello']
11
+ s.files = FileList["[A-Z]*", "{lib,test}/**/*"]
12
+ end
13
+ Jeweler::GemcutterTasks.new
14
+ rescue LoadError
15
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
16
+ end
17
+
18
+ Rake::TestTask.new do |t|
19
+ t.libs << "test"
20
+ t.test_files = FileList['test/*-test.rb']
21
+ t.verbose = true
22
+ end
23
+
24
+ require 'rake/rdoctask'
25
+ desc "Generate documentation"
26
+ Rake::RDocTask.new do |rd|
27
+ rd.main = "README.rdoc"
28
+ rd.rdoc_files.include("README.rdoc", "lib/**/*.rb")
29
+ rd.rdoc_dir = 'rdoc'
30
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.5
@@ -0,0 +1,438 @@
1
+ =begin
2
+ Copyright notice
3
+ =============================================================================
4
+ Copyright (c) 2009 Kristan 'Krispy' Uccello <krispy@soldierofcode.com> - Soldier Of Code
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in
14
+ all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ THE SOFTWARE.
23
+ ==============================================================================
24
+
25
+ This middleware is based on work initialy done by Jackson Miller with his
26
+ parse-user-agent project (http://github.com/jaxn/parse-user-agent). Jackson
27
+ can be reached at jackson.h.miller@gmail.com - parse-user-agent uses a
28
+ MIT/X Consortium License
29
+
30
+ ==============================================================================
31
+ LICENSE
32
+ ==============================================================================
33
+ see LICENSE file for details
34
+
35
+ =end
36
+ module SoldierOfCode
37
+
38
+ class SpyVsSpy
39
+
40
+ class Middleware
41
+ def initialize(app=nil)
42
+ @app = app
43
+ end
44
+
45
+ def call(env)
46
+
47
+ http_user_agent = env['HTTP_USER_AGENT']
48
+
49
+ env['soldierofcode.spy-vs-spy'] = ParseUserAgent.new(http_user_agent)
50
+
51
+ @app.call(env)
52
+ end
53
+
54
+
55
+ end
56
+
57
+ class Version
58
+ attr_accessor :major, :minor, :sub
59
+
60
+ def to_s
61
+ [major, minor, sub].compact.join('.')
62
+ end
63
+
64
+ def update(major = nil, minor = nil, sub = nil)
65
+ @major, @minor, @sub = major, minor, sub
66
+ end
67
+
68
+ end
69
+
70
+ class OS
71
+ def initialize(os_string)
72
+ @os_string = os_string
73
+ @exact_os = (match = /(Mac OS X|Linux|Windows)/.match(@os_string)) ? match[1] : nil
74
+ end
75
+
76
+ def to_s
77
+ @os_string
78
+ end
79
+
80
+ def osx?
81
+ @exact_os == 'Mac OS X'
82
+ end
83
+
84
+ def linux?
85
+ @exact_os == 'Linux'
86
+ end
87
+
88
+ def windows?
89
+ @exact_os == 'Windows'
90
+ end
91
+ end
92
+
93
+ SafariSpecialCases = {
94
+ "1.0" => ["85.5", "85.6", "85.7"],
95
+ "1,0.3" => ["85.8.1", "85.8", "85"],
96
+ "1.2" => ["125", "125.1"],
97
+ "1.2.2" => ["85.8", "125.7", "125.8"],
98
+ "1.2.3" => ["100", "125.9"],
99
+ "1.2.4" => ["125", "125.11", "125.12", "125.12_Adobe", "125.5.5"],
100
+ "1.3" => ["312", "312.3.1"],
101
+ "1.3.1" => ["312.3.3", "312.3.1", "312.3", "125.8", "125.9"],
102
+ "1.3.2" => ["312.3.3", "312.5", "312.6", "312.5_Adobe"],
103
+ "2.0" => ["412", "412.2.2", "412.2_Adobe"],
104
+ "2.0.1" => ["412.5", "412.6", "412.5_Adobe"],
105
+ "2.0.2" => ["416.13", "416.12", "312", "416.13_Adobe", "416.12_Adobe", "412.5"],
106
+ "2.0.3" => ["417.9.3", "417.8_Adobe", "417.9.2", "417.8", "412.2"],
107
+ "2.0.4" => ["419.3"],
108
+ "3.0" => ["523.13", "522.11.3", "523.12.9", "523.6.1", "522.11.1", "522.11", "522.8.3", "522.7"],
109
+ "3.0.1" => ["522.12.2"],
110
+ "3.0.2" => ["522.13.1", "522.12"],
111
+ "3.0.3" => ["522.15.5", "523.6", "522.12.1"],
112
+ "3.0.4" => ["523.11", "523.12.2", "523.10", "523.10.6", "523.15", "523.12"],
113
+ "3.1.1" => ["525.17", "525.18", "525.20"],
114
+ "3.2.1" => ["525.27.1"]
115
+ }
116
+
117
+ attr_reader :browser, :os_version, :version, :mobile_browser, :console_browser, :agent, :os
118
+
119
+ #
120
+ #
121
+ # =======================================
122
+ # description:
123
+ # ----------------
124
+ #
125
+ # params:
126
+ # ----------------
127
+ #
128
+ # returns:
129
+ # ----------------
130
+ def initialize(agent)
131
+
132
+ @agent = agent
133
+
134
+ pass1 = Regexp.new("^([^\\(]*)?[ ]*?(\\([^\\)]*\\))?[ ]*([^\\(]*)?[ ]*?(\\([^\\)]*\\))?[ ]*(.*)")
135
+ if matches = pass1.match(agent)
136
+
137
+ @product_token = matches[1] || ''
138
+ @detail = matches[2] || ''
139
+ @engine = matches[3] || ''
140
+ @renderer = matches[4] || ''
141
+ @identifier = matches[5] || ''
142
+
143
+ @platform = identify_platform(agent)
144
+ @mobile = is_mobile?(agent)
145
+ @os = OS.new(@detail)
146
+ @version = Version.new
147
+
148
+ [:safari, :firefox, :ie, :opera, :netscape].each do |type|
149
+ send(:"process_#{type}", agent)
150
+ break if complete?
151
+ end
152
+
153
+ end
154
+ end
155
+ #
156
+ #
157
+ # =======================================
158
+ # description:
159
+ # ----------------
160
+ #
161
+ # params:
162
+ # ----------------
163
+ #
164
+ # returns:
165
+ # ----------------
166
+ def identify_platform(agent)
167
+ (match = /(PLAYSTATION 3|wii|PlayStation Portable|Xbox|iPhone|iPod|BlackBerry|Android|HTC-|LG|Motorola|Nokia|Treo|Pre\/|Samsung|SonyEricsson)/.match(agent)) ?
168
+ match[1] : 'Desktop'
169
+ end
170
+
171
+ #
172
+ #
173
+ # =======================================
174
+ # description:
175
+ # ----------------
176
+ #
177
+ # params:
178
+ # ----------------
179
+ #
180
+ # returns:
181
+ # ----------------
182
+ def is_mobile?(agent)
183
+ /(iPhone|iPod|BlackBerry|Android|HTC-|LG|Motorola|Nokia|Treo|Pre\/|Samsung|SonyEricsson)/.match(agent)
184
+ end
185
+
186
+ def complete?
187
+ @browser && @version.major
188
+ end
189
+
190
+ #
191
+ #
192
+ # =======================================
193
+ # description:
194
+ # ----------------
195
+ #
196
+ # params:
197
+ # ----------------
198
+ #
199
+ # returns:
200
+ # ----------------
201
+ def process_safari(agent_string)
202
+ @identifier = @engine if @identifier == ""
203
+
204
+ if agent_string.include?("Safari")
205
+ @browser = "Safari"
206
+ end
207
+
208
+ if @identifier.include?("Safari") || @renderer.include?("Safari") || @detail.include?("iPhone") || @identifier.include?("iPhone")
209
+ @browser = "Safari"
210
+
211
+ identifier_sub = nil
212
+ @identifier.gsub(/[\\:\?'"%!@#\$\^&\*\(\)\+]/, '').split(" ").each do |ident|
213
+ identifier_sub = ident.sub("Safari\/", "") if ident.include?("Safari")
214
+ identifier_sub.gsub!(/[\+]/, '') if identifier_sub && identifier_sub.include?("+")
215
+ end
216
+ if identifier_sub == nil && @renderer.include?("Safari")
217
+ renderer_gsub_gsub = @renderer.sub("\(", "").sub("\)", "")
218
+ renderer_gsub_gsub.strip.split(",").each do |sec|
219
+ identifier_sub = sec.sub("Safari\/", "").strip if sec.include?("Safari")
220
+ end
221
+ end
222
+
223
+ SafariSpecialCases.each do |k, v|
224
+ version_numbers = k.gsub(",", ".").split(".")
225
+ v.each do |num|
226
+ if identifier_sub == num
227
+ @version.update(*version_numbers)
228
+ end
229
+ break if @version.major
230
+ end
231
+ # Special case 58.8 - check WebKit numbers
232
+ # Special case 312 - check AppleWebKit
233
+ # Special case 419.3 - could me mobile v3 check AppleWebKit for 420+
234
+
235
+ engine_id = @engine[/AppleWebKit\/([0-9.]+)/, 1]
236
+
237
+ case identifier_sub
238
+ when "85.8"
239
+ case engine_id
240
+ when '125.2' then @version.update('1', '2', '2')
241
+ end
242
+ when "125"
243
+ case engine_id
244
+ when '124' then @version.update('1', '2')
245
+ when '312.5.2' then @version.update('1', '3', '1')
246
+ when '312.1' then @version.update('1', '3')
247
+ end
248
+ when '412.5'
249
+ case engine_id
250
+ when '416.12' then @version.update('2','0','2')
251
+ end
252
+ when '416.13'
253
+ case engine_id
254
+ when '417.9' then @version.update('2','0','3')
255
+ end
256
+ when '412.2'
257
+ case engine_id
258
+ when '412.6' then @version.update('2','0')
259
+ end
260
+ when '312.3.1'
261
+ case engine_id
262
+ when '312.1' then @version.update('1', '3')
263
+ when '312.5.1' then @version.update('1', '3', '1')
264
+ end
265
+ when "125.8"
266
+ case engine_id
267
+ when '312.5.1' then @version.update('1', '3', '1')
268
+ when '125.2' then @version.update('1', '2', '2')
269
+ end
270
+ when "125.9"
271
+ case engine_id
272
+ when '125.4' then @version.update('1', '2', '3')
273
+ when '125.5' then @version.update('1', '2', '3')
274
+ end
275
+ when "312"
276
+ case engine_id
277
+ when '416.11' then @version.update('2', '0', '2')
278
+ end
279
+ when "312.3.3"
280
+ case engine_id
281
+ when '312.8' then @version.update('1', '3', '2')
282
+ end
283
+ when "419.3"
284
+ case engine_id
285
+ when "420" then @version.update('3', '0')
286
+ end
287
+ end
288
+
289
+ if (identifier_sub == "Safari") || (@identifier == "Safari/")then
290
+ case engine_id
291
+ when "418.9", "418.8"
292
+ @version.update('2', '0', '4')
293
+ end
294
+ end
295
+
296
+ ident_sub = nil
297
+ if @identifier.include?("Version") then
298
+ @identifier.split(" ").each do |ident|
299
+ ident_sub = ident.sub("Version\/", "") if ident.include?("Version")
300
+ if ident_sub then
301
+ @version.update(*ident_sub.split(/[.,]/))
302
+ end
303
+ end
304
+ end
305
+
306
+ if @identifier == "Safari/412 Privoxy/3.0" then
307
+ @version.major = '2'
308
+ @version.minor = '0'
309
+ @version.sub = nil
310
+ end
311
+
312
+ break if @version.major
313
+ end
314
+ end
315
+
316
+ if @browser == nil && @os.osx? && agent_string.include?("AppleWebKit")
317
+ @browser = "Safari"
318
+ end
319
+ end
320
+
321
+ #
322
+ #
323
+ # =======================================
324
+ # description:
325
+ # ----------------
326
+ #
327
+ # params:
328
+ # ----------------
329
+ #
330
+ # returns:
331
+ # ----------------
332
+ def process_ie(agent)
333
+ # @detail
334
+ if agent.include?("MSIE")
335
+ @browser = "MSIE"
336
+ end
337
+ if @detail.include?("MSIE")
338
+ @detail.gsub(/[\\:\?'"%!@#\$\^&\*\(\)\+]/, '').split(";").each do |sec|
339
+ if sec.strip.index("MSIE ") == 0
340
+ @version.update(*sec.strip.sub("MSIE ", "").gsub(/0(\d)/, '0.\1').split(/[.,]/))
341
+ end
342
+
343
+ break if @version.major
344
+ end
345
+ end
346
+
347
+ unless @version.major
348
+ if match = /MSIE ([6789])\.0/.match(agent)
349
+ @browser = "MSIE"
350
+ @version.major = match[1]
351
+ @version.minor = '0'
352
+ end
353
+ end
354
+ end
355
+
356
+ #
357
+ #
358
+ # =======================================
359
+ # description:
360
+ # ----------------
361
+ #
362
+ # params:
363
+ # ----------------
364
+ #
365
+ # returns:
366
+ # ----------------
367
+ def process_firefox(agent)
368
+ @identifier = @engine if @identifier == ""
369
+
370
+ if agent.include?("Firefox")
371
+ @browser = "Firefox"
372
+ end
373
+
374
+ if @identifier.include?("Firefox") || @renderer.include?("Firefox") || @engine.include?("Firefox")
375
+ @browser = "Firefox"
376
+
377
+ identifier_sub = nil
378
+ @identifier.gsub(/[\\:\?'"%!@#\$\^&\*\(\)\+]/, '').split(" ").find do |ident|
379
+ if ident.include?("Firefox")
380
+ identifier_sub = ident.sub("Firefox\/", "").sub("Gecko/", "")
381
+ identifier_sub.gsub!(/[\+]/, '')
382
+ end
383
+ identifier_sub
384
+ end
385
+ if identifier_sub.nil? && @renderer.include?("Firefox")
386
+ renderer_gsub_gsub = @renderer.sub("\(", "").sub("\)", "")
387
+ renderer_gsub_gsub.strip.split(",").each do |sec|
388
+ identifier_sub = sec.sub("Firefox\/", "").strip if sec.include?("Firefox")
389
+ end
390
+ end
391
+ if identifier_sub.nil? && @engine.include?("Firefox")
392
+ @engine.gsub(/[\\:\?'"%!@#\$\^&\*\(\)\+]/, '').split(" ").each do |ident|
393
+ identifier_sub = ident.sub("Firefox\/", "").sub("Gecko/", "") if ident.include?("Firefox")
394
+ identifier_sub.gsub!(/[\+]/, '') if identifier_sub && identifier_sub.include?("+")
395
+ end
396
+ end
397
+
398
+ identifier_sub.gsub!(/;.*/, '')
399
+
400
+ if identifier_sub
401
+ @version.update(*identifier_sub.split("."))
402
+ end
403
+ end
404
+ end
405
+
406
+ #
407
+ #
408
+ # =======================================
409
+ # description:
410
+ # ----------------
411
+ #
412
+ # params:
413
+ # ----------------
414
+ #
415
+ # returns:
416
+ # ----------------
417
+ def process_opera(agent)
418
+
419
+ end
420
+
421
+ #
422
+ #
423
+ # =======================================
424
+ # description:
425
+ # ----------------
426
+ #
427
+ # params:
428
+ # ----------------
429
+ #
430
+ # returns:
431
+ # ----------------
432
+ def process_netscape(agent)
433
+
434
+ end
435
+ end
436
+ end
437
+
438
+ SOC = SoldierOfCode