bindata 1.2.2 → 1.3.1
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.
Potentially problematic release.
This version of bindata might be problematic. Click here for more details.
- data/ChangeLog +12 -0
- data/NEWS +53 -0
- data/Rakefile +2 -1
- data/examples/NBT.txt +149 -0
- data/examples/ip_address.rb +1 -2
- data/examples/list.rb +124 -0
- data/examples/nbt.rb +195 -0
- data/lib/bindata.rb +4 -3
- data/lib/bindata/alignment.rb +86 -0
- data/lib/bindata/array.rb +21 -29
- data/lib/bindata/base.rb +82 -81
- data/lib/bindata/base_primitive.rb +66 -48
- data/lib/bindata/choice.rb +18 -28
- data/lib/bindata/deprecated.rb +17 -0
- data/lib/bindata/dsl.rb +25 -15
- data/lib/bindata/int.rb +2 -2
- data/lib/bindata/io.rb +8 -6
- data/lib/bindata/offset.rb +91 -0
- data/lib/bindata/primitive.rb +22 -11
- data/lib/bindata/record.rb +40 -10
- data/lib/bindata/sanitize.rb +15 -30
- data/lib/bindata/string.rb +16 -17
- data/lib/bindata/stringz.rb +0 -1
- data/lib/bindata/struct.rb +17 -6
- data/lib/bindata/trace.rb +52 -0
- data/lib/bindata/wrapper.rb +28 -6
- data/manual.haml +56 -10
- data/manual.md +318 -113
- data/spec/alignment_spec.rb +61 -0
- data/spec/array_spec.rb +139 -178
- data/spec/base_primitive_spec.rb +86 -111
- data/spec/base_spec.rb +200 -172
- data/spec/bits_spec.rb +45 -53
- data/spec/choice_spec.rb +91 -87
- data/spec/deprecated_spec.rb +36 -14
- data/spec/float_spec.rb +16 -68
- data/spec/int_spec.rb +26 -27
- data/spec/io_spec.rb +105 -105
- data/spec/lazy_spec.rb +50 -50
- data/spec/primitive_spec.rb +36 -36
- data/spec/record_spec.rb +134 -134
- data/spec/registry_spec.rb +34 -38
- data/spec/rest_spec.rb +8 -11
- data/spec/skip_spec.rb +9 -17
- data/spec/spec_common.rb +4 -0
- data/spec/string_spec.rb +92 -115
- data/spec/stringz_spec.rb +41 -74
- data/spec/struct_spec.rb +132 -153
- data/spec/system_spec.rb +115 -60
- data/spec/wrapper_spec.rb +63 -31
- data/tasks/pkg.rake +1 -1
- metadata +15 -7
data/lib/bindata/sanitize.rb
CHANGED
@@ -13,37 +13,20 @@ module BinData
|
|
13
13
|
# SanitizedParameters is a hash-like collection of parameters. Its purpose
|
14
14
|
# it to recursively sanitize the parameters of an entire BinData object chain
|
15
15
|
# at a single time.
|
16
|
-
class SanitizedParameters
|
16
|
+
class SanitizedParameters < Hash
|
17
17
|
|
18
18
|
def initialize(parameters, the_class)
|
19
|
+
parameters.each_pair { |key, value| self[key.to_sym] = value }
|
20
|
+
|
19
21
|
@all_sanitized = false
|
20
22
|
@the_class = the_class
|
21
|
-
|
22
|
-
@parameters = {}
|
23
|
-
parameters.each { |key, value| @parameters[key.to_sym] = value }
|
24
|
-
|
25
23
|
ensure_no_nil_values
|
26
24
|
end
|
27
25
|
|
28
|
-
|
29
|
-
@parameters.size
|
30
|
-
end
|
31
|
-
alias_method :size, :length
|
32
|
-
|
33
|
-
def [](key)
|
34
|
-
@parameters[key]
|
35
|
-
end
|
36
|
-
|
37
|
-
def []=(key, value)
|
38
|
-
@parameters[key] = value unless @all_sanitized
|
39
|
-
end
|
40
|
-
|
41
|
-
def has_parameter?(key)
|
42
|
-
@parameters.has_key?(key)
|
43
|
-
end
|
26
|
+
alias_method :has_parameter?, :has_key?
|
44
27
|
|
45
28
|
def needs_sanitizing?(key)
|
46
|
-
parameter =
|
29
|
+
parameter = self[key]
|
47
30
|
|
48
31
|
parameter and not parameter.is_a?(SanitizedParameter)
|
49
32
|
end
|
@@ -67,9 +50,9 @@ module BinData
|
|
67
50
|
|
68
51
|
def move_unknown_parameters_to(dest)
|
69
52
|
unless @all_sanitized
|
70
|
-
unused_keys =
|
53
|
+
unused_keys = keys - @the_class.accepted_parameters.all
|
71
54
|
unused_keys.each do |key|
|
72
|
-
dest[key] =
|
55
|
+
dest[key] = delete(key)
|
73
56
|
end
|
74
57
|
end
|
75
58
|
end
|
@@ -85,7 +68,7 @@ module BinData
|
|
85
68
|
private
|
86
69
|
|
87
70
|
def ensure_no_nil_values
|
88
|
-
|
71
|
+
each do |key, value|
|
89
72
|
if value.nil?
|
90
73
|
raise ArgumentError,
|
91
74
|
"parameter '#{key}' has nil value in #{@the_class}"
|
@@ -95,7 +78,7 @@ module BinData
|
|
95
78
|
|
96
79
|
def merge_default_parameters!
|
97
80
|
@the_class.default_parameters.each do |key, value|
|
98
|
-
|
81
|
+
self[key] ||= value
|
99
82
|
end
|
100
83
|
end
|
101
84
|
|
@@ -215,8 +198,10 @@ module BinData
|
|
215
198
|
end
|
216
199
|
end
|
217
200
|
|
218
|
-
def instantiate(parent = nil)
|
219
|
-
@obj_class.new(@obj_params
|
201
|
+
def instantiate(value = nil, parent = nil)
|
202
|
+
@factory ||= @obj_class.new(@obj_params)
|
203
|
+
|
204
|
+
@factory.new(value, parent)
|
220
205
|
end
|
221
206
|
end
|
222
207
|
#----------------------------------------------------------------------------
|
@@ -228,8 +213,8 @@ module BinData
|
|
228
213
|
end
|
229
214
|
attr_reader :name
|
230
215
|
|
231
|
-
def instantiate(parent = nil)
|
232
|
-
@prototype.instantiate(parent)
|
216
|
+
def instantiate(value = nil, parent = nil)
|
217
|
+
@prototype.instantiate(value, parent)
|
233
218
|
end
|
234
219
|
end
|
235
220
|
#----------------------------------------------------------------------------
|
data/lib/bindata/string.rb
CHANGED
@@ -10,24 +10,24 @@ module BinData
|
|
10
10
|
#
|
11
11
|
# obj = BinData::String.new(:read_length => 5)
|
12
12
|
# obj.read(data)
|
13
|
-
# obj
|
13
|
+
# obj #=> "abcde"
|
14
14
|
#
|
15
15
|
# obj = BinData::String.new(:length => 6)
|
16
16
|
# obj.read(data)
|
17
|
-
# obj
|
18
|
-
# obj.
|
19
|
-
# obj
|
20
|
-
# obj.
|
21
|
-
# obj
|
17
|
+
# obj #=> "abcdef"
|
18
|
+
# obj.assign("abcdefghij")
|
19
|
+
# obj #=> "abcdef"
|
20
|
+
# obj.assign("abcd")
|
21
|
+
# obj #=> "abcd\000\000"
|
22
22
|
#
|
23
23
|
# obj = BinData::String.new(:length => 6, :trim_padding => true)
|
24
|
-
# obj.
|
25
|
-
# obj
|
24
|
+
# obj.assign("abcd")
|
25
|
+
# obj #=> "abcd"
|
26
26
|
# obj.to_binary_s #=> "abcd\000\000"
|
27
27
|
#
|
28
28
|
# obj = BinData::String.new(:length => 6, :pad_char => 'A')
|
29
|
-
# obj.
|
30
|
-
# obj
|
29
|
+
# obj.assign("abcd")
|
30
|
+
# obj #=> "abcdAA"
|
31
31
|
# obj.to_binary_s #=> "abcdAA"
|
32
32
|
#
|
33
33
|
# == Parameters
|
@@ -83,12 +83,11 @@ module BinData
|
|
83
83
|
end
|
84
84
|
|
85
85
|
def snapshot
|
86
|
-
# override to
|
86
|
+
# override to trim padding
|
87
87
|
result = super
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
if get_parameter(:trim_padding) == true
|
88
|
+
result = clamp_to_length(result)
|
89
|
+
|
90
|
+
if get_parameter(:trim_padding)
|
92
91
|
result = trim_padding(result)
|
93
92
|
end
|
94
93
|
result
|
@@ -97,7 +96,7 @@ module BinData
|
|
97
96
|
#---------------
|
98
97
|
private
|
99
98
|
|
100
|
-
def
|
99
|
+
def clamp_to_length(str)
|
101
100
|
len = eval_parameter(:length) || str.length
|
102
101
|
if str.length == len
|
103
102
|
str
|
@@ -113,7 +112,7 @@ module BinData
|
|
113
112
|
end
|
114
113
|
|
115
114
|
def value_to_binary_string(val)
|
116
|
-
|
115
|
+
clamp_to_length(val)
|
117
116
|
end
|
118
117
|
|
119
118
|
def read_and_return_value(io)
|
data/lib/bindata/stringz.rb
CHANGED
data/lib/bindata/struct.rb
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
require 'bindata/base'
|
2
2
|
|
3
3
|
module BinData
|
4
|
+
|
5
|
+
class Base
|
6
|
+
optional_parameter :onlyif # Used by Struct
|
7
|
+
end
|
8
|
+
|
4
9
|
# A Struct is an ordered collection of named data objects.
|
5
10
|
#
|
6
11
|
# require 'bindata'
|
@@ -119,7 +124,12 @@ module BinData
|
|
119
124
|
end
|
120
125
|
|
121
126
|
def hidden_field_names(hidden)
|
122
|
-
(hidden || []).collect
|
127
|
+
(hidden || []).collect do |h|
|
128
|
+
unless Symbol === h
|
129
|
+
warn "Hidden field '#{h}' should be provided as a symbol. Using strings is deprecated"
|
130
|
+
end
|
131
|
+
h.to_s # TODO: change this to sym
|
132
|
+
end
|
123
133
|
end
|
124
134
|
|
125
135
|
def ensure_field_names_are_valid(field_names)
|
@@ -142,10 +152,11 @@ module BinData
|
|
142
152
|
end
|
143
153
|
end
|
144
154
|
|
145
|
-
def
|
146
|
-
|
155
|
+
def initialize_shared_instance
|
156
|
+
@field_names = get_parameter(:fields).field_names.freeze
|
157
|
+
end
|
147
158
|
|
148
|
-
|
159
|
+
def initialize_instance
|
149
160
|
@field_objs = []
|
150
161
|
end
|
151
162
|
|
@@ -219,7 +230,7 @@ module BinData
|
|
219
230
|
|
220
231
|
def do_num_bytes #:nodoc:
|
221
232
|
instantiate_all_objs
|
222
|
-
sum_num_bytes_for_all_fields
|
233
|
+
sum_num_bytes_for_all_fields
|
223
234
|
end
|
224
235
|
|
225
236
|
#---------------
|
@@ -258,7 +269,7 @@ module BinData
|
|
258
269
|
def instantiate_obj_at(index)
|
259
270
|
if @field_objs[index].nil?
|
260
271
|
field = get_parameter(:fields)[index]
|
261
|
-
@field_objs[index] = field.instantiate(self)
|
272
|
+
@field_objs[index] = field.instantiate(nil, self)
|
262
273
|
end
|
263
274
|
end
|
264
275
|
|
data/lib/bindata/trace.rb
CHANGED
@@ -25,10 +25,14 @@ module BinData
|
|
25
25
|
# This is useful for debugging a BinData declaration.
|
26
26
|
def trace_reading(io = STDERR, &block)
|
27
27
|
@tracer = Tracer.new(io)
|
28
|
+
BasePrimitive.turn_on_tracing
|
29
|
+
Choice.turn_on_tracing
|
28
30
|
if block_given?
|
29
31
|
begin
|
30
32
|
block.call
|
31
33
|
ensure
|
34
|
+
BasePrimitive.turn_off_tracing
|
35
|
+
Choice.turn_off_tracing
|
32
36
|
@tracer = nil
|
33
37
|
end
|
34
38
|
end
|
@@ -39,4 +43,52 @@ module BinData
|
|
39
43
|
end
|
40
44
|
|
41
45
|
module_function :trace_reading, :trace_message
|
46
|
+
|
47
|
+
class BasePrimitive < BinData::Base
|
48
|
+
class << self
|
49
|
+
def turn_on_tracing
|
50
|
+
alias_method :hook_after_do_read, :trace_value
|
51
|
+
end
|
52
|
+
|
53
|
+
def turn_off_tracing
|
54
|
+
alias_method :hook_after_do_read, :null_method
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
#---------------
|
59
|
+
private
|
60
|
+
|
61
|
+
def null_method; end
|
62
|
+
|
63
|
+
def trace_value
|
64
|
+
BinData::trace_message do |tracer|
|
65
|
+
value_string = _value.inspect
|
66
|
+
tracer.trace_obj(debug_name, value_string)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
class Choice < BinData::Base
|
72
|
+
class << self
|
73
|
+
def turn_on_tracing
|
74
|
+
alias_method :hook_before_do_read, :trace_selection
|
75
|
+
end
|
76
|
+
|
77
|
+
def turn_off_tracing
|
78
|
+
alias_method :hook_before_do_read, :null_method
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
#---------------
|
83
|
+
private
|
84
|
+
|
85
|
+
def null_method; end
|
86
|
+
|
87
|
+
def trace_selection
|
88
|
+
BinData::trace_message do |tracer|
|
89
|
+
selection_string = eval_parameter(:selection).inspect
|
90
|
+
tracer.trace_obj("#{debug_name}-selection-", selection_string)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
42
94
|
end
|
data/lib/bindata/wrapper.rb
CHANGED
@@ -9,8 +9,10 @@ module BinData
|
|
9
9
|
#
|
10
10
|
# class Uint8Array < BinData::Wrapper
|
11
11
|
# default_parameter :initial_element_value => 0
|
12
|
-
#
|
13
|
-
#
|
12
|
+
#
|
13
|
+
# array :initial_length => 2 do
|
14
|
+
# uint8 :initial_value => :initial_element_value
|
15
|
+
# end
|
14
16
|
# end
|
15
17
|
#
|
16
18
|
# arr = Uint8Array.new
|
@@ -40,11 +42,9 @@ module BinData
|
|
40
42
|
|
41
43
|
mandatory_parameter :wrapped
|
42
44
|
|
43
|
-
def
|
44
|
-
super
|
45
|
-
|
45
|
+
def initialize_instance
|
46
46
|
prototype = get_parameter(:wrapped)
|
47
|
-
@wrapped = prototype.instantiate(self)
|
47
|
+
@wrapped = prototype.instantiate(nil, self)
|
48
48
|
end
|
49
49
|
|
50
50
|
def clear #:nodoc:
|
@@ -82,5 +82,27 @@ module BinData
|
|
82
82
|
def do_num_bytes #:nodoc:
|
83
83
|
@wrapped.do_num_bytes
|
84
84
|
end
|
85
|
+
|
86
|
+
#---------------
|
87
|
+
private
|
88
|
+
|
89
|
+
def extract_args(args)
|
90
|
+
klass = wrapped_class
|
91
|
+
if klass
|
92
|
+
klass.arg_extractor.extract(klass, args)
|
93
|
+
else
|
94
|
+
super
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def wrapped_class
|
99
|
+
return nil if self.class.field.nil?
|
100
|
+
|
101
|
+
begin
|
102
|
+
RegisteredClasses.lookup(self.class.field.type, self.class.endian)
|
103
|
+
rescue BinData::UnRegisteredTypeError
|
104
|
+
nil
|
105
|
+
end
|
106
|
+
end
|
85
107
|
end
|
86
108
|
end
|
data/manual.haml
CHANGED
@@ -2,16 +2,18 @@
|
|
2
2
|
%html{ :xmlns => "http://www.w3.org/1999/xhtml", "xml:lang" => "en", :lang => "en" }
|
3
3
|
%head
|
4
4
|
%meta{ :content => "text/html; charset=iso-8859-1", "http-equiv" => "Content-Type" }
|
5
|
+
%meta{ :description =>"How to easily parse binary data in Ruby" }
|
6
|
+
%meta{ :keywords =>"ruby, parse binary data, read binary data" }
|
5
7
|
%title
|
6
|
-
BinData Reference Manual
|
8
|
+
Parsing Binary Data in Ruby - BinData Reference Manual
|
7
9
|
:javascript
|
8
10
|
var TINY={};function T$(i){return document.getElementById(i)}function T$$(e,p){return p.getElementsByTagName(e)}TINY.accordion=function(){function slider(n){this.n=n;this.a=[]}slider.prototype.init=function(t,e,m,o,k){var a=T$(t),i=s=0,n=a.childNodes,l=n.length;this.s=k||0;this.m=m||0;for(i;i<l;i++){var v=n[i];if(v.nodeType!=3){this.a[s]={};this.a[s].h=h=T$$(e,v)[0];this.a[s].c=c=T$$('div',v)[0];h.onclick=new Function(this.n+'.pr(0,'+s+')');if(o==s){h.className=this.s;c.style.height='auto';c.d=1}else{c.style.height=0;c.d=-1}s++}}this.l=s};slider.prototype.pr=function(f,d){for(var i=0;i<this.l;i++){var h=this.a[i].h,c=this.a[i].c,k=c.style.height;k=k=='auto'?1:parseInt(k);clearInterval(c.t);if((k!=1&&c.d==-1)&&(f==1||i==d)){c.style.height='';c.m=c.offsetHeight;c.style.height=k+'px';c.d=1;h.className=this.s;su(c,1)}else if(k>0&&(f==-1||this.m||i==d)){c.d=-1;h.className='';su(c,-1)}}};function su(c){c.t=setInterval(function(){sl(c)},20)};function sl(c){var h=c.offsetHeight,d=c.d==1?c.m-h:h;c.style.height=h+(Math.ceil(d/5)*c.d)+'px';c.style.opacity=h/c.m;c.style.filter='alpha(opacity='+h*100/c.m+')';if((c.d==1&&h>=c.m)||(c.d!=1&&h==1)){if(c.d==1){c.style.height='auto'}clearInterval(c.t)}};return{slider:slider}}();
|
9
11
|
|
10
12
|
var menu1, menu2, menu3, menu4, menu5, menu6;
|
11
|
-
var menu7, menu8, menu9, menu10, menu11;
|
13
|
+
var menu7, menu8, menu9, menu10, menu11, menu12, menu13;
|
12
14
|
|
13
15
|
function init_accordion() {
|
14
|
-
menu1 = new TINY.accordion.slider("menu1"); menu1.init("menu1","a",1
|
16
|
+
menu1 = new TINY.accordion.slider("menu1"); menu1.init("menu1","a",1,-1);
|
15
17
|
menu2 = new TINY.accordion.slider("menu2"); menu2.init("menu2","a",1,-1);
|
16
18
|
menu3 = new TINY.accordion.slider("menu3"); menu3.init("menu3","a",1,-1);
|
17
19
|
menu4 = new TINY.accordion.slider("menu4"); menu4.init("menu4","a",1,-1);
|
@@ -22,6 +24,8 @@
|
|
22
24
|
menu9 = new TINY.accordion.slider("menu9"); menu9.init("menu9","a",1,-1);
|
23
25
|
menu10 = new TINY.accordion.slider("menu10"); menu10.init("menu10","a",1,-1);
|
24
26
|
menu11 = new TINY.accordion.slider("menu11"); menu11.init("menu11","a",1,-1);
|
27
|
+
menu12 = new TINY.accordion.slider("menu12"); menu11.init("menu12","a",1,-1);
|
28
|
+
menu13 = new TINY.accordion.slider("menu13"); menu11.init("menu13","a",1,-1);
|
25
29
|
};
|
26
30
|
window.onload = init_accordion;
|
27
31
|
|
@@ -125,6 +129,11 @@
|
|
125
129
|
License
|
126
130
|
.acc-section
|
127
131
|
.acc-content
|
132
|
+
%li
|
133
|
+
%a{ :href => "#donate" }
|
134
|
+
Donate
|
135
|
+
.acc-section
|
136
|
+
.acc-content
|
128
137
|
%li
|
129
138
|
%a{ :href => "#installation" }
|
130
139
|
Installation
|
@@ -168,13 +177,23 @@
|
|
168
177
|
.acc-section
|
169
178
|
.acc-content
|
170
179
|
%li
|
171
|
-
%a{ :href => "#
|
172
|
-
|
180
|
+
%a{ :href => "#dependencies_between_fields" }
|
181
|
+
Dependencies between fields
|
182
|
+
.acc-section
|
183
|
+
.acc-content
|
184
|
+
%li
|
185
|
+
%a{ :href => "#nested_records" }
|
186
|
+
Nested Records
|
173
187
|
.acc-section
|
174
188
|
.acc-content
|
175
189
|
%li
|
176
|
-
%a{ :href => "#
|
177
|
-
|
190
|
+
%a{ :href => "#bitfields" }
|
191
|
+
Bitfields
|
192
|
+
.acc-section
|
193
|
+
.acc-content
|
194
|
+
%li
|
195
|
+
%a{ :href => "#optional_fields" }
|
196
|
+
Optional fields
|
178
197
|
.acc-section
|
179
198
|
.acc-content
|
180
199
|
%li
|
@@ -241,22 +260,49 @@
|
|
241
260
|
Arrays
|
242
261
|
.acc-section
|
243
262
|
.acc-content
|
263
|
+
%ul.level2#menu9
|
264
|
+
%li
|
265
|
+
%a{ :href => "#array_syntax" }
|
266
|
+
Array syntax
|
267
|
+
.acc-section
|
268
|
+
.acc-content
|
269
|
+
%li
|
270
|
+
%a{ :href => "#array_parameters" }
|
271
|
+
Array parameters
|
272
|
+
.acc-section
|
273
|
+
.acc-content
|
244
274
|
%li
|
245
275
|
%a{ :href => "#choices" }
|
246
276
|
Choices
|
247
277
|
.acc-section
|
248
278
|
.acc-content
|
279
|
+
%ul.level2#menu10
|
280
|
+
%li
|
281
|
+
%a{ :href => "#choice_syntax" }
|
282
|
+
Choice syntax
|
283
|
+
.acc-section
|
284
|
+
.acc-content
|
285
|
+
%li
|
286
|
+
%a{ :href => "#choice_parameters" }
|
287
|
+
Choice parameters
|
288
|
+
.acc-section
|
289
|
+
.acc-content
|
249
290
|
%li
|
250
291
|
%a{ :href => "#advanced_topics" }
|
251
292
|
Advanced Topics
|
252
293
|
.acc-section
|
253
294
|
.acc-content
|
254
|
-
%ul.level2#
|
295
|
+
%ul.level2#menu11
|
255
296
|
%li
|
256
297
|
%a{ :href => "#skipping_over_unused_data" }
|
257
298
|
Skipping over unused data
|
258
299
|
.acc-section
|
259
300
|
.acc-content
|
301
|
+
%li
|
302
|
+
%a{ :href => "#bitaligned_records" }
|
303
|
+
Bit-aligned Records
|
304
|
+
.acc-section
|
305
|
+
.acc-content
|
260
306
|
%li
|
261
307
|
%a{ :href => "#wrappers" }
|
262
308
|
Wrappers
|
@@ -267,7 +313,7 @@
|
|
267
313
|
Parameterizing User Defined Types
|
268
314
|
.acc-section
|
269
315
|
.acc-content
|
270
|
-
%ul.level3#
|
316
|
+
%ul.level3#menu12
|
271
317
|
%li
|
272
318
|
%a{ :href => "#mandatory_parameters" }
|
273
319
|
Mandatory Parameters
|
@@ -283,7 +329,7 @@
|
|
283
329
|
Debugging
|
284
330
|
.acc-section
|
285
331
|
.acc-content
|
286
|
-
%ul.level3#
|
332
|
+
%ul.level3#menu13
|
287
333
|
%li
|
288
334
|
%a{ :href => "#tracing" }
|
289
335
|
Tracing
|