rb-wartslib 0.9.11 → 0.9.12

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,3 +1,9 @@
1
+ version 0.9.12, 2008-01-16
2
+ * renamed Warts::Trace#each_attempt to each_response
3
+ * renamed Warts::Trace#each_hop_and_attempt to each_hop_and_response
4
+ * the previous each_attempt and each_hop_and_attempt methods are still
5
+ available as aliases, though deprecated
6
+
1
7
  version 0.9.11, 2007-11-29:
2
8
  * added more sample code to the 'bin' subdirectory
3
9
  * added GPLv2+ license header to sample code
@@ -24,7 +24,7 @@
24
24
  ## along with this program; if not, write to the Free Software
25
25
  ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26
26
  ##
27
- ## $Id: extract-trace-addrs,v 1.1 2007/11/30 01:14:48 youngh Exp $
27
+ ## $Id: extract-trace-addrs,v 1.2 2007/12/08 00:56:04 youngh Exp $
28
28
  #############################################################################
29
29
 
30
30
  require 'rubygems'
@@ -63,10 +63,10 @@ end
63
63
  def extract_addresses(trace, addresses)
64
64
  dest_response = trace.find_dest_response
65
65
 
66
- trace.each_hop_and_attempt do |hop, attempt, exists|
66
+ trace.each_hop_and_response do |hop, response, exists|
67
67
  next unless exists
68
68
  break if dest_response && hop == dest_response[0]
69
- addresses[trace.hop_addr(hop, attempt)] += 1
69
+ addresses[trace.hop_addr(hop, response)] += 1
70
70
  end
71
71
 
72
72
  addresses[trace.dst] += 1 if dest_response
data/bin/scdump CHANGED
@@ -20,7 +20,7 @@
20
20
  ## along with this program; if not, write to the Free Software
21
21
  ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
22
  ##
23
- ## $Id: scdump,v 1.12 2007/11/29 23:57:41 youngh Exp $
23
+ ## $Id: scdump,v 1.13 2007/12/08 00:43:19 youngh Exp $
24
24
  #############################################################################
25
25
 
26
26
  require 'rubygems'
@@ -64,7 +64,7 @@ def show_trace(trace)
64
64
  path_complete = "I"
65
65
  if dest_response
66
66
  hop = 0
67
- trace.each do |hop, attempt, exists|
67
+ trace.each do |hop, response, exists|
68
68
  break if !exists || hop >= dest_response[0]
69
69
  end
70
70
  path_complete = "C" if hop == dest_response[0]
@@ -79,15 +79,15 @@ def show_trace(trace)
79
79
  trace.each_hop do |hop, exists|
80
80
  if exists
81
81
  hop_str = ""
82
- trace.each_attempt(hop) do |attempt|
82
+ trace.each_response(hop) do |response|
83
83
  # sc_analysis_dump compatibility
84
84
  next if dest_response &&
85
- hop == dest_response[0] && attempt == dest_response[1]
85
+ hop == dest_response[0] && response == dest_response[1]
86
86
 
87
87
  hop_str << ";" unless hop_str.empty?
88
- hop_str << trace.hop_addr(hop, attempt)
89
- hop_str << "," << trace.hop_rtt_str(hop, attempt)
90
- hop_str << "," << trace.hop_probe_id(hop, attempt).to_s
88
+ hop_str << trace.hop_addr(hop, response)
89
+ hop_str << "," << trace.hop_rtt_str(hop, response)
90
+ hop_str << "," << trace.hop_probe_id(hop, response).to_s
91
91
  end
92
92
 
93
93
  unless hop_str.empty?
@@ -20,7 +20,7 @@
20
20
  ## along with this program; if not, write to the Free Software
21
21
  ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
22
  ##
23
- ## $Id: stat-traces,v 1.1 2007/11/30 01:14:48 youngh Exp $
23
+ ## $Id: stat-traces,v 1.3 2007/12/08 00:56:04 youngh Exp $
24
24
  #############################################################################
25
25
 
26
26
  require 'rubygems'
@@ -28,14 +28,62 @@ require 'ostruct'
28
28
  require 'wartslib'
29
29
 
30
30
  class Stats
31
- attr_accessor :traces, :responding, :complete, :stop_reason
31
+ attr_accessor :traces, :responding, :complete, :stop_reason, :icmp_reason
32
32
  attr_accessor :hop_histogram, :zero_dead
33
33
 
34
+ # Based on http://www.iana.org/assignments/icmp-parameters
35
+ ICMP_TYPE_NAMES = {
36
+ 0 => "Echo Reply",
37
+ 3 => "Dest Unreachable",
38
+ 4 => "Source Quench",
39
+ 5 => "Redirect",
40
+ 11 => "Time Exceeded",
41
+ 12 => "Parameter Problem"
42
+ }
43
+
44
+ ICMP_CODE_NAMES = Hash.new { |h,k| h[k] = {} }
45
+ ICMP_CODE_NAMES.merge!({
46
+ 0 => {
47
+ 0 => "" # No Code
48
+ },
49
+ 3 => {
50
+ 0 => "Net Unreachable",
51
+ 1 => "Host Unreachable",
52
+ 2 => "Protocol Unreachable",
53
+ 3 => "Port Unreachable",
54
+ 4 => "Fragmentation Needed and DF Set",
55
+ 5 => "Source Route Failed",
56
+ 6 => "Destination Network Unknown",
57
+ 7 => "Destination Host Unknown",
58
+ 8 => "Source Host Isolated",
59
+ 9 => "Admin Prohibited: Dest Network",
60
+ 10 => "Admin Prohibited: Dest Host",
61
+ 11 => "Dest Network Unreachable for TOS",
62
+ 12 => "Dest Host Unreachable for TOS",
63
+ 13 => "Administratively Prohibited",
64
+ 14 => "Host Precedence Violation",
65
+ 15 => "Precedence Cutoff in Effect"
66
+ },
67
+ 4 => {
68
+ 0 => "" # No Code
69
+ },
70
+ 11 => {
71
+ 0 => "TTL Exceeded in Transit",
72
+ 1 => "Fragment Reassembly Time Exceeded"
73
+ },
74
+ 12 => {
75
+ 0 => "Pointer Indicates the Error",
76
+ 1 => "Missing a Required Option",
77
+ 2 => "Bad Length"
78
+ }
79
+ })
80
+
34
81
  def initialize
35
82
  @traces = 0
36
83
  @responding = 0
37
84
  @complete = 0
38
85
  @stop_reason = Hash.new 0
86
+ @icmp_reason = Hash.new 0 # "#{icmp_type} #{icmp_code}"
39
87
 
40
88
  # from scamper_trace.h:SCAMPER_TRACE_STOP_*
41
89
  @stop_text = {
@@ -59,21 +107,45 @@ class Stats
59
107
  puts "%8d complete (%.1f%%)" % [@complete, pct(@complete, @traces)]
60
108
  puts "%8d dead traces with zero hop count (%.1f%%)" %
61
109
  [ @zero_dead, pct(@zero_dead, @traces) ]
110
+
62
111
  puts
63
- stop_reason.to_a.sort.each do |k, v|
112
+ @stop_reason.to_a.sort.each do |k, v|
64
113
  puts "%8d stop reason %d, %s" % [v, k, @stop_text[k]]
65
114
  end
115
+
116
+ puts
117
+ @icmp_reason.to_a.map{ |k, v| [k >> 8, k & 0xFF, v] }.sort.each do |t, c, v|
118
+ type_name = ICMP_TYPE_NAMES[t]
119
+ code_name = ICMP_CODE_NAMES[t][c]
120
+ names = ""
121
+ if type_name
122
+ names = " (#{type_name}"
123
+ if code_name
124
+ names += ": #{code_name}" unless code_name == ""
125
+ else
126
+ names += ": ?"
127
+ end
128
+ names += ")"
129
+ end
130
+ puts "%8d icmp type %d, code %d%s" % [v, t, c, names]
131
+ end
132
+
66
133
  puts
67
134
  @hop_histogram.to_a.sort.each do |k, v|
68
135
  puts "%8d %d hops" % [v, k]
69
136
  end
70
137
  end
71
138
 
139
+ def add_icmp_reason(icmp_type, icmp_code)
140
+ @icmp_reason[icmp_type << 8 | icmp_code] += 1
141
+ end
142
+
72
143
  def add(other)
73
144
  @traces += other.traces
74
145
  @responding += other.responding
75
146
  @complete += other.complete
76
147
  other.stop_reason.each { |k,v| @stop_reason[k] += v }
148
+ other.icmp_reason.each { |k,v| @icmp_reason[k] += v }
77
149
  other.hop_histogram.each { |k,v| @hop_histogram[k] += v }
78
150
  @zero_dead += other.zero_dead
79
151
  end
@@ -97,6 +169,17 @@ ARGV.each do |path|
97
169
  stats.responding += 1 if trace.dest_responded?
98
170
  stats.complete += 1 if trace.complete?
99
171
  stats.stop_reason[trace.stop_reason] += 1
172
+
173
+ # XXX This doesn't work properly for TCP traces, because TCP traces with
174
+ # stop reason == 1 (completed) have TCP flags but no ICMP type/code
175
+ # values for the response from the destination.
176
+ trace.each_hop_and_response do |hop, response, exists|
177
+ next unless exists
178
+ icmp_type = trace.hop_icmp_type hop, response
179
+ icmp_code = trace.hop_icmp_code hop, response
180
+ stats.add_icmp_reason icmp_type, icmp_code
181
+ end
182
+
100
183
  stats.hop_histogram[trace.path_length] += 1
101
184
  stats.zero_dead += 1 if trace.stop_reason == 5 && trace.hop_count == 0
102
185
  end
data/bin/wdump CHANGED
@@ -25,7 +25,7 @@
25
25
  ## along with this program; if not, write to the Free Software
26
26
  ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27
27
  ##
28
- ## $Id: wdump,v 1.10 2007/11/29 23:57:24 youngh Exp $
28
+ ## $Id: wdump,v 1.11 2007/12/08 00:43:48 youngh Exp $
29
29
  #############################################################################
30
30
 
31
31
  require 'rubygems'
@@ -58,13 +58,13 @@ def show_trace(trace)
58
58
  show_attr trace, name
59
59
  end
60
60
 
61
- trace.each do |hop, attempt, exists|
61
+ trace.each do |hop, response, exists|
62
62
  unless exists
63
- puts "hop #{hop}, attempt 0: *"
63
+ puts "hop #{hop}, response 0: *"
64
64
  next
65
65
  end
66
66
 
67
- puts "hop #{hop}, attempt #{attempt}"
67
+ puts "hop #{hop}, response #{response}"
68
68
  [
69
69
  :hop_addr,
70
70
  :hop_flags,
@@ -80,7 +80,7 @@ def show_trace(trace)
80
80
  :hop_rtt_usec
81
81
  ].each do |name|
82
82
  print " "
83
- show_attr trace, name, hop, attempt
83
+ show_attr trace, name, hop, response
84
84
  end
85
85
  end
86
86
  end
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ ##############################################################################
4
+ ## Generate a web page showing Ruby scripts with syntax highlighting.
5
+ ##
6
+ ## $Id: gen-code-html,v 1.2 2007/12/04 22:57:31 youngh Exp $
7
+ ##############################################################################
8
+
9
+ require 'rubygems'
10
+ require 'ostruct'
11
+ require 'optparse'
12
+
13
+ require 'syntax/convertors/html'
14
+
15
+ $options = OpenStruct.new
16
+
17
+ opts = OptionParser.new
18
+ opts.banner = "Usage: gen-code-html [options] <script> ..."
19
+
20
+ opts.on("-s", "--snippet", TrueClass,
21
+ "generate HTML fragment for code snippet") do |v|
22
+ $options.snippet = v
23
+ end
24
+
25
+ begin
26
+ ARGV.replace opts.parse(*ARGV)
27
+ rescue OptionParser::ParseError
28
+ $stderr.puts "ERROR: " + $!
29
+ $stderr.puts opts
30
+ exit 1
31
+ end
32
+
33
+ #===========================================================================
34
+
35
+ ARGV.each do |path|
36
+ convertor = Syntax::Convertors::HTML.for_syntax "ruby"
37
+ html = convertor.convert(File.read(path))
38
+
39
+ if $options.snippet
40
+ html.sub!(/^<pre/, "<pre class=\"ruby snippet\"")
41
+ else
42
+ html.sub!(/^<pre/, "<pre class=\"ruby\"")
43
+ end
44
+
45
+ basename = File.basename path
46
+ out = File.open basename + ".html", "w"
47
+
48
+ unless $options.snippet
49
+ out.puts <<HEADER
50
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
51
+ <html>
52
+ <head>
53
+ <title>rb-wartslib: Sample Script: #{basename}</title>
54
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
55
+ <link rel="stylesheet" type="text/css" href="layout.css">
56
+ <link rel="stylesheet" type="text/css" href="style.css">
57
+ <link rel="stylesheet" type="text/css" href="ruby.css">
58
+ </head>
59
+
60
+ <body class="twikiViewPage">
61
+
62
+ <div class="twikiTopBar">
63
+ <div class="twikiTopBarContents">
64
+ <h1 class="pagetitle">rb-wartslib: Ruby Warts Library</h1>
65
+ </div>
66
+ </div>
67
+
68
+ <a name="PageTop"></a>
69
+ <div class="twikiMiddleContainer">
70
+ <div class="twikiLeftBar">
71
+ <div class="twikiLeftBarContents">
72
+ <ul>
73
+ <li> <a class="twikiLink" href="http://rb-wartslib.rubyforge.org/">Project Home Page</a></li>
74
+ <li> <a class="twikiLink" href="http://rubyforge.org/projects/rb-wartslib/">RubyForge Page</a></li>
75
+ </ul>
76
+ <hr>
77
+ <ul>
78
+ <li> <a class="twikiLink" href="index.html#installation">Installation</a></li>
79
+ <li> <a class="twikiLink" href="tutorial.html">Tutorial</a></li>
80
+ <li> <a class="twikiLink" href="reference.html">Class Reference</a></li>
81
+ <li> <a class="twikiLink" href="samples.html"><b>Sample Scripts</b></a></li>
82
+ </ul>
83
+ <hr>
84
+ <ul>
85
+ <li> <a class="twikiLink" href="index.html#contact">Contact</a></li>
86
+ <li> <a class="twikiLink" href="index.html#license">License Note</a></li>
87
+ </ul>
88
+ </div></div></div>
89
+
90
+ <div class="twikiMain">
91
+ <div class="twikiTopic">
92
+ <h1>Sample Script: #{basename}</h1>
93
+ HEADER
94
+ end
95
+
96
+ out.puts html
97
+
98
+ unless $options.snippet
99
+ out.puts <<FOOTER
100
+ <!---->
101
+ </div></div>
102
+ </body></html>
103
+ FOOTER
104
+ end
105
+
106
+ out.close
107
+ end
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ puts "<pre class=\"snippet\">"
4
+ puts "<span class=\"shell_command\"></span>"
5
+ $stdin.each do |line|
6
+ print "<span class=\"command_output\">", line.chomp!, "</span>", "\n"
7
+ end
8
+ puts "</pre>"
9
+
@@ -0,0 +1,4 @@
1
+ #!/bin/sh
2
+
3
+ rm tut-*.rb.html
4
+ ./gen-code-html -s tut-*.rb
@@ -0,0 +1,221 @@
1
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2
+ <html>
3
+ <head>
4
+ <title>rb-wartslib: Ruby Warts Library</title>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
6
+ <link rel="stylesheet" type="text/css" href="layout.css">
7
+ <link rel="stylesheet" type="text/css" href="style.css">
8
+ </head>
9
+
10
+ <body>
11
+
12
+ <div class="twikiTopBar">
13
+ <div class="twikiTopBarContents">
14
+ <h1 class="pagetitle">rb-wartslib: Ruby Warts Library</h1>
15
+ </div>
16
+ </div>
17
+
18
+ <a name="PageTop"></a>
19
+ <div class="twikiLeftBar">
20
+ <div class="twikiLeftBarContents">
21
+ <ul>
22
+ <li> <a href="index.html"><b>Project Home Page</b></a></li>
23
+ <li> <a href="http://rubyforge.org/projects/rb-wartslib/">RubyForge Page</a></li>
24
+ </ul>
25
+ <hr>
26
+ <ul>
27
+ <li> <a href="#installation">Installation</a></li>
28
+ <li> <a href="tutorial.html">Tutorial</a></li>
29
+ <li> <a href="reference.html">Class Reference</a></li>
30
+ <li> <a href="samples.html">Sample Scripts</a></li>
31
+ </ul>
32
+ <hr>
33
+ <ul>
34
+ <li> <a href="#contact">Contact</a></li>
35
+ <li> <a href="#license">License</a></li>
36
+ </ul>
37
+ </div></div>
38
+
39
+ <div class="twikiMain">
40
+ <div class="twikiTopic">
41
+ <h2>What is it?</h2>
42
+ <p>
43
+ <b>This is a Ruby extension for reading/writing warts files.</b> Warts
44
+ files are output by <a href="http://www.wand.net.nz/scamper/">scamper</a>,
45
+ a tool for performing large-scale traceroute- and ping-based network
46
+ measurements. You can also use this extension to read (but not write)
47
+ <a href="http://www.caida.org/tools/utilities/arts/">arts++</a> files
48
+ produced by <a href="http://www.caida.org/tools/measurement/skitter/index.xml">skitter</a>.
49
+ </p>
50
+
51
+ <p>
52
+ This extension only provides a thin wrapper around the C-language routines
53
+ in <i>scamper</i> for reading/writing warts files. But this is all you
54
+ need to write pleasant little Ruby scripts that compute various statistics
55
+ about collected traces, convert IP paths to AS paths, and perform myriad
56
+ other processing for which, let's be honest, <b>life is too short to be
57
+ writing in C</b>. Write your analysis scripts with <i>rb-wartslib</i>, and
58
+ with a Zen-like peace, spend your newly discovered free time with your
59
+ friends, family, and your neglected small furry pet animals.
60
+ </p>
61
+
62
+ <h2>But Ruby is slow!</h2>
63
+
64
+ <p>
65
+ Yes, it is. But it is also <b>fast enough.</b> For example, some of the
66
+ sample Ruby analysis scripts only take 1&frac12; to 2 times longer than an
67
+ equivalent written in C/C++ because all the warts I/O is done in C code.
68
+ If you're computing the hyperbolic Lagrangian bleibenvalues, then it might
69
+ be a bit slow with Ruby, but what are computers for after all? More
70
+ importantly, it's much easier to write <b>correct</b> code with Ruby than
71
+ C, and correctness is far more important than speed with data analysis.
72
+ </p>
73
+
74
+ <h2>Limitations</h2>
75
+
76
+ <p>
77
+ Although you can use this extension to write out trace data to warts files,
78
+ you can't use this extension itself to create completely new traces in
79
+ memory--that is, you can only write out traces you've read in from a file.
80
+ Furthermore, any read-in data is immutable, with a few careful exceptions,
81
+ because the principle purpose of this extension is to support the analysis
82
+ of existing data rather than the creation of new data. The ability to
83
+ write out (unmodified) traces is still useful for filtering out traces and
84
+ for re-organizing traces into a different set of files (for example, into
85
+ daily files, or into separate files by the type of probing method used).
86
+ </p>
87
+
88
+ <h2><a name="installation"></a>Installation</h2>
89
+
90
+ <p>
91
+ If <i>rb-wartslib</i> were a typical Ruby Gem, you would install it with
92
+ </p>
93
+
94
+ <pre>
95
+ $ sudo gem install rb-wartslib
96
+ </pre>
97
+
98
+ <p>
99
+ However, <i>rb-wartslib</i> must be compiled against the <i>scamper</i>
100
+ source code so there are a few additional steps.
101
+ </p>
102
+
103
+ <p>
104
+ First, download and build <i>scamper;</i> for example:
105
+ </p>
106
+
107
+ <pre>
108
+ $ wget http://www.wand.net.nz/scamper/scamper-cvs-20070523i.tar.gz
109
+ $ tar xvzf scamper-cvs-20070523i.tar.gz
110
+ $ cd scamper-cvs-20070523i
111
+ $ make -f Makefile.gnu (if you're on Linux or MacOS X)
112
+ $ make (if you're on FreeBSD)
113
+ </pre>
114
+
115
+ <p>
116
+ That will build <code>libscamperfile.a</code>, which is what <i>rb-wartslib</i>
117
+ links against.
118
+ </p>
119
+
120
+ <p>
121
+ Now build and install <i>rb-wartslib:</i>
122
+ </p>
123
+
124
+ <pre>
125
+ $ SCAMPER=/Users/youngh/scamper-cvs-20070523h
126
+ (set the above to the directory where you built scamper)
127
+ $ sudo gem install rb-wartslib -- --with-scamper-include=$SCAMPER
128
+ --with-scamper-lib=$SCAMPER
129
+ </pre>
130
+
131
+ <p>
132
+ That's it.
133
+ </p>
134
+
135
+ <h2>Documentation</h2>
136
+
137
+ <p>
138
+ Start by reading the <a href="tutorial.html">tutorial</a>, which discusses
139
+ fundamental concepts and covers most of the common uses. Then look over
140
+ the <a href="samples.html">sample analysis scripts</a>. For a more
141
+ in-depth documentation of the Ruby classes, see
142
+ the <a href="reference.html">reference documentation</a>.
143
+ </p>
144
+
145
+ <p>
146
+ The sample scripts are also included in the <code>bin</code> subdirectory
147
+ of the <i>rb-wartslib</i> distribution file. To find them on your system,
148
+ execute the following after installing <i>rb-wartslib:</i>
149
+ </p>
150
+
151
+ <pre>
152
+ $ gem contents rb-wartslib
153
+ /opt/local/lib/ruby/gems/1.8/gems/rb-wartslib-0.9.11/bin/count-traces
154
+ /opt/local/lib/ruby/gems/1.8/gems/rb-wartslib-0.9.11/bin/create-aspath
155
+ /opt/local/lib/ruby/gems/1.8/gems/rb-wartslib-0.9.11/bin/extract-trace-addrs
156
+ ...
157
+ </pre>
158
+
159
+
160
+ <h2><a name="contact"></a>Contact</h2>
161
+
162
+ <p>
163
+ <i>rb-wartslib</i> is written and maintained by
164
+ <a href="http://www.caida.org/~youngh/">Young Hyun</a> as a part of
165
+ <a href="http://www.caida.org">CAIDA</a>'s work on
166
+ the <a href="http://www.caida.org/projects/ark/"> Archipelago Measurement
167
+ Infrastructure</a>. You may contact him at <code>youngh AT
168
+ rubyforge.org</code>, or use the tracker/forums at
169
+ the <a href="http://rubyforge.org/projects/rb-wartslib/">RubyForge project
170
+ page</a> for getting help.
171
+ </p>
172
+
173
+ <p>
174
+ Please direct <i>scamper</i> questions, including problems building it,
175
+ to <a href="http://www.wand.net.nz/personDetail.php?id=13">Matthew
176
+ Luckie</a>:
177
+ </p>
178
+
179
+ <pre>
180
+ mjl (squigglyatthingie) wand (period) net (period) nz
181
+ </pre>
182
+
183
+
184
+ <h2><a name="license"></a>License</h2>
185
+
186
+ <p>
187
+ The <i>rb-wartslib</i> binding code is licensed under
188
+ <a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.html">GPLv2</a>
189
+ <b>or later</b>, but this binding must link with <i>scamper</i>, which is
190
+ licensed under GPLv2 <b>only</b> (no later). Therefore, when your own Ruby
191
+ program makes calls into <i>rb-wartslib</i> (that is, "links"
192
+ to <i>rb-wartslib</i>), then <i>rb-wartslib</i> is effectively under GPLv2
193
+ <b>only</b>, so your client program must be GPLv2 compatible. However, if
194
+ you merely re-use any of the <i>rb-wartslib</i> source code in your own
195
+ programs (but none of the <i>scamper</i> source code), then the license is
196
+ GPLv2 <b>or later</b>. For example, if you wish to use
197
+ the <i>rb-wartslib</i> source code as a template for writing an extension
198
+ of your own (that provides a binding to something else), then the code is
199
+ licensed under GPLv2 or later.
200
+ </p>
201
+
202
+ <p>
203
+ If you don't distribute your client program, then the requirements of the
204
+ GPL do not apply to your client program. In particular, if you write an
205
+ internal tool used only in your organization, then it does <b>not</b> have
206
+ to be released under the GPL to use <i>rb-wartslib</i>; it can have
207
+ whatever license you choose. This freedom is intentionally allowed by the
208
+ GPL.
209
+ </p>
210
+
211
+ <h2>Acknowledgments</h2>
212
+
213
+ <p>
214
+ The design of these web pages draws on one of the styles used by the
215
+ <a href="http://twiki.org/">TWiki</a> wiki tool.
216
+ </p>
217
+
218
+
219
+ <!---->
220
+ </div></div>
221
+ </body></html>