schemacop 0.0.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.
@@ -0,0 +1,405 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
6
+ <title>
7
+ File: README
8
+
9
+ &mdash; Documentation by YARD 0.8.7.6
10
+
11
+ </title>
12
+
13
+ <link rel="stylesheet" href="css/style.css" type="text/css" charset="utf-8" />
14
+
15
+ <link rel="stylesheet" href="css/common.css" type="text/css" charset="utf-8" />
16
+
17
+ <script type="text/javascript" charset="utf-8">
18
+ hasFrames = window.top.frames.main ? true : false;
19
+ relpath = '';
20
+ framesUrl = "frames.html#!file.README.html";
21
+ </script>
22
+
23
+
24
+ <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
25
+
26
+ <script type="text/javascript" charset="utf-8" src="js/app.js"></script>
27
+
28
+
29
+ </head>
30
+ <body>
31
+ <div id="header">
32
+ <div id="menu">
33
+
34
+ <a href="_index.html">Index</a> &raquo;
35
+ <span class="title">File: README</span>
36
+
37
+
38
+ <div class="noframes"><span class="title">(</span><a href="." target="_top">no frames</a><span class="title">)</span></div>
39
+ </div>
40
+
41
+ <div id="search">
42
+
43
+ <a class="full_list_link" id="class_list_link"
44
+ href="class_list.html">
45
+ Class List
46
+ </a>
47
+
48
+ <a class="full_list_link" id="method_list_link"
49
+ href="method_list.html">
50
+ Method List
51
+ </a>
52
+
53
+ <a class="full_list_link" id="file_list_link"
54
+ href="file_list.html">
55
+ File List
56
+ </a>
57
+
58
+ </div>
59
+ <div class="clear"></div>
60
+ </div>
61
+
62
+ <iframe id="search_frame"></iframe>
63
+
64
+ <div id="content"><div id='filecontents'><p><a href="https://travis-ci.org/sitrox/schemacop"><img src="https://travis-ci.org/sitrox/schemacop.svg?branch=master" alt="Build Status"></a></p>
65
+
66
+ <h1>Schemacop</h1>
67
+
68
+ <p>Schemacop validates ruby structures consisting of nested hashes and arrays
69
+ against simple schema definitions.</p>
70
+
71
+ <p>Example:</p>
72
+
73
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_schema'>schema</span> <span class='op'>=</span> <span class='lbrace'>{</span>
74
+ <span class='label'>type:</span> <span class='symbol'>:hash</span><span class='comma'>,</span>
75
+ <span class='label'>hash:</span> <span class='lbrace'>{</span>
76
+ <span class='label'>first_name:</span> <span class='symbol'>:string</span><span class='comma'>,</span>
77
+ <span class='label'>last_name:</span> <span class='symbol'>:string</span>
78
+ <span class='rbrace'>}</span>
79
+ <span class='rbrace'>}</span>
80
+
81
+ <span class='id identifier rubyid_data'>data</span> <span class='op'>=</span> <span class='lbrace'>{</span>
82
+ <span class='label'>first_name:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>John</span><span class='tstring_end'>&#39;</span></span><span class='comma'>,</span>
83
+ <span class='label'>last_name:</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>Doe</span><span class='tstring_end'>&#39;</span></span>
84
+ <span class='rbrace'>}</span>
85
+
86
+ <span class='const'>Schemacop</span><span class='period'>.</span><span class='id identifier rubyid_validate!'>validate!</span><span class='lparen'>(</span><span class='id identifier rubyid_schema'>schema</span><span class='comma'>,</span> <span class='id identifier rubyid_data'>data</span><span class='rparen'>)</span>
87
+ </code></pre>
88
+
89
+ <h2>Installation</h2>
90
+
91
+ <p>To install the <strong>Schemacop</strong> gem:</p>
92
+
93
+ <pre class="code sh"><code class="sh">$ gem install schemacop
94
+ </code></pre>
95
+
96
+ <p>To install it using <code>bundler</code> (recommended for any application), add it
97
+ to your <code>Gemfile</code>:</p>
98
+
99
+ <pre class="code ruby"><code class="ruby"><span class='id identifier rubyid_gem'>gem</span> <span class='tstring'><span class='tstring_beg'>&#39;</span><span class='tstring_content'>schemacop</span><span class='tstring_end'>&#39;</span></span>
100
+ </code></pre>
101
+
102
+ <h2>Basic usage</h2>
103
+
104
+ <p>Schemacop&#39;s interface is very simple:</p>
105
+
106
+ <pre class="code ruby"><code class="ruby"><span class='const'>Schemacop</span><span class='period'>.</span><span class='id identifier rubyid_validate!'>validate!</span><span class='lparen'>(</span><span class='id identifier rubyid_schema'>schema</span><span class='comma'>,</span> <span class='id identifier rubyid_data'>data</span><span class='rparen'>)</span>
107
+ </code></pre>
108
+
109
+ <p>It will throw an exception if either the schema is wrong or the given data does
110
+ not comply with the schema. See section <em>Exceptions</em> for more information.</p>
111
+
112
+ <h2>Defining schemas</h2>
113
+
114
+ <p>Schemacop can validate recursive structures of arrays nested into hashes and
115
+ vice-versa. &#39;Leaf-nodes&#39; can be of any data type, but their internal structure
116
+ is not validated.</p>
117
+
118
+ <p>Schema definitions are always a hash, even if they specify an array. Each level
119
+ of a definition hash has to define a type.</p>
120
+
121
+ <p>You can specify any type, but only the types <code>:hash</code> and <code>:array</code> allow you to
122
+ specify a sub structure.</p>
123
+
124
+ <h3>Defining hashes</h3>
125
+
126
+ <p>Once a level is defined as a hash (<code>type: :hash</code>), you can provide the key
127
+ <code>hash</code> which in turn specifies the keys contained in that hash:</p>
128
+
129
+ <pre class="code ruby"><code class="ruby"><span class='lbrace'>{</span>
130
+ <span class='label'>type:</span> <span class='symbol'>:hash</span><span class='comma'>,</span>
131
+ <span class='label'>hash:</span> <span class='lbrace'>{</span>
132
+ <span class='label'>first_name:</span> <span class='lbrace'>{</span> <span class='label'>type:</span> <span class='symbol'>:string</span> <span class='rbrace'>}</span><span class='comma'>,</span>
133
+ <span class='label'>last_name:</span> <span class='lbrace'>{</span> <span class='label'>type:</span> <span class='symbol'>:string</span> <span class='rbrace'>}</span>
134
+ <span class='rbrace'>}</span>
135
+ <span class='rbrace'>}</span>
136
+ </code></pre>
137
+
138
+ <p>If you don&#39;t provide the <code>:hash</code> key, the hash won&#39;t be validated (other than
139
+ the verification that it really is a hash):</p>
140
+
141
+ <pre class="code ruby"><code class="ruby"><span class='lbrace'>{</span> <span class='label'>type:</span> <span class='symbol'>:hash</span> <span class='rbrace'>}</span>
142
+ </code></pre>
143
+
144
+ <p>Hash definitions can be nested deeply:</p>
145
+
146
+ <pre class="code ruby"><code class="ruby"><span class='lbrace'>{</span>
147
+ <span class='label'>type:</span> <span class='symbol'>:hash</span><span class='comma'>,</span>
148
+ <span class='label'>hash:</span> <span class='lbrace'>{</span>
149
+ <span class='label'>name:</span> <span class='lbrace'>{</span>
150
+ <span class='label'>type:</span> <span class='symbol'>:hash</span><span class='comma'>,</span>
151
+ <span class='label'>hash:</span> <span class='lbrace'>{</span>
152
+ <span class='label'>first_name:</span> <span class='lbrace'>{</span> <span class='label'>type:</span> <span class='symbol'>:string</span> <span class='rbrace'>}</span><span class='comma'>,</span>
153
+ <span class='label'>last_name:</span> <span class='lbrace'>{</span> <span class='label'>type:</span> <span class='symbol'>:string</span> <span class='rbrace'>}</span>
154
+ <span class='rbrace'>}</span>
155
+ <span class='rbrace'>}</span>
156
+ <span class='rbrace'>}</span>
157
+ <span class='rbrace'>}</span>
158
+ </code></pre>
159
+
160
+ <h3>Defining arrays</h3>
161
+
162
+ <p>When you define a level as an array (<code>type: :array</code>), you can provide further
163
+ specification of the array&#39;s contents uby supplying the key <code>:array</code>:</p>
164
+
165
+ <pre class="code ruby"><code class="ruby"><span class='lbrace'>{</span>
166
+ <span class='label'>type:</span> <span class='symbol'>:array</span><span class='comma'>,</span>
167
+ <span class='label'>array:</span> <span class='lbrace'>{</span>
168
+ <span class='label'>type:</span> <span class='symbol'>:string</span>
169
+ <span class='rbrace'>}</span>
170
+ <span class='rbrace'>}</span>
171
+ </code></pre>
172
+
173
+ <p>This example would define an array of strings.</p>
174
+
175
+ <p>Arrays can nest hashes and vice-versa:</p>
176
+
177
+ <pre class="code ruby"><code class="ruby"><span class='lbrace'>{</span>
178
+ <span class='label'>type:</span> <span class='symbol'>:array</span><span class='comma'>,</span>
179
+ <span class='label'>array:</span> <span class='lbrace'>{</span>
180
+ <span class='label'>type:</span> <span class='symbol'>:string</span>
181
+ <span class='rbrace'>}</span>
182
+ <span class='rbrace'>}</span>
183
+ </code></pre>
184
+
185
+ <p>If you don&#39;t provide the <code>:array</code> key, the array contents won&#39;t be validated:</p>
186
+
187
+ <pre class="code ruby"><code class="ruby"><span class='lbrace'>{</span> <span class='label'>type:</span> <span class='symbol'>:array</span> <span class='rbrace'>}</span>
188
+ </code></pre>
189
+
190
+ <h2>Types</h2>
191
+
192
+ <p>For each level in your schema, you can specify the type in one of the following
193
+ manors:</p>
194
+
195
+ <ul>
196
+ <li>A ruby class:</li>
197
+ </ul>
198
+
199
+ <pre class="code ruby"><code class="ruby"> <span class='lbrace'>{</span> <span class='label'>type:</span> <span class='const'>String</span> <span class='rbrace'>}</span>
200
+ </code></pre>
201
+
202
+ <ul>
203
+ <li>A type alias (see <span class='object_link'><a href="Schemacop/Validator.html#TYPE_ALIASES-constant" title="Schemacop::Validator::TYPE_ALIASES (constant)">Schemacop::Validator::TYPE_ALIASES</a></span> for a full list of
204
+ available type aliasses):</li>
205
+ </ul>
206
+
207
+ <pre class="code ruby"><code class="ruby"> <span class='lbrace'>{</span> <span class='label'>type:</span> <span class='symbol'>:boolean</span> <span class='rbrace'>}</span>
208
+ </code></pre>
209
+
210
+ <ul>
211
+ <li>A list of ruby classes or type aliases:</li>
212
+ </ul>
213
+
214
+ <pre class="code ruby"><code class="ruby"> <span class='lbrace'>{</span> <span class='label'>type:</span> <span class='lbracket'>[</span><span class='const'>String</span><span class='comma'>,</span> <span class='symbol'>:integer</span><span class='rbracket'>]</span> <span class='rbrace'>}</span>
215
+ </code></pre>
216
+
217
+ <p>When specifying more than one type, it is validated that the given data
218
+ structure matches <em>one</em> of the given types.</p>
219
+
220
+ <p>If you specify both <code>:array</code> and <code>:hash</code> in such a type array, you can provide
221
+ a specification for both <code>array</code> and <code>hash</code> types:</p>
222
+
223
+ <pre class="code ruby"><code class="ruby"> <span class='lbrace'>{</span>
224
+ <span class='label'>type:</span> <span class='lbracket'>[</span><span class='symbol'>:array</span><span class='comma'>,</span> <span class='symbol'>:hash</span><span class='rbracket'>]</span><span class='comma'>,</span>
225
+ <span class='label'>array:</span> <span class='lbrace'>{</span>
226
+ <span class='label'>type:</span> <span class='symbol'>:string</span>
227
+ <span class='rbrace'>}</span><span class='comma'>,</span>
228
+ <span class='label'>hash:</span> <span class='lbrace'>{</span>
229
+ <span class='label'>first_name:</span> <span class='symbol'>:string</span>
230
+ <span class='rbrace'>}</span>
231
+ <span class='rbrace'>}</span>
232
+ </code></pre>
233
+
234
+ <p>It will then determine which specification to use based on the actual data.</p>
235
+
236
+ <h2>Null and required</h2>
237
+
238
+ <p>Using the optional parameters <code>required</code> and <code>null</code>, you can control whether a
239
+ specific substructure must be provided (<code>required</code>) and if it can be <code>nil</code>
240
+ (<code>null</code>).</p>
241
+
242
+ <p>These two parameters can be combined in any way.</p>
243
+
244
+ <h3>Required validation</h3>
245
+
246
+ <p>When validating with <code>required = false</code>, it means that the whole key can be
247
+ omitted. As an example:</p>
248
+
249
+ <pre class="code ruby"><code class="ruby"><span class='comment'># Successfully validates data hash: {}
250
+ </span><span class='lbrace'>{</span>
251
+ <span class='label'>type:</span> <span class='symbol'>:hash</span><span class='comma'>,</span>
252
+ <span class='label'>hash:</span> <span class='lbrace'>{</span>
253
+ <span class='label'>first_name:</span> <span class='lbrace'>{</span> <span class='label'>type:</span> <span class='symbol'>:string</span><span class='comma'>,</span> <span class='label'>required:</span> <span class='kw'>false</span> <span class='rbrace'>}</span>
254
+ <span class='rbrace'>}</span>
255
+ <span class='rbrace'>}</span>
256
+ </code></pre>
257
+
258
+ <h3>Null validation</h3>
259
+
260
+ <p>When validating with <code>null = true</code>, the key must still be present, but it can
261
+ also be <code>nil</code>.</p>
262
+
263
+ <pre class="code ruby"><code class="ruby"><span class='comment'># Successfully validates data hash: { first_name: nil }
264
+ </span><span class='lbrace'>{</span>
265
+ <span class='label'>type:</span> <span class='symbol'>:hash</span><span class='comma'>,</span>
266
+ <span class='label'>hash:</span> <span class='lbrace'>{</span>
267
+ <span class='label'>first_name:</span> <span class='lbrace'>{</span> <span class='label'>type:</span> <span class='symbol'>:string</span><span class='comma'>,</span> <span class='label'>null:</span> <span class='kw'>false</span> <span class='rbrace'>}</span>
268
+ <span class='rbrace'>}</span>
269
+ <span class='rbrace'>}</span>
270
+ </code></pre>
271
+
272
+ <h2>Allowed values</h2>
273
+
274
+ <p>For any level, you can optionally specify an array of values that are allowed.</p>
275
+
276
+ <p>For example:</p>
277
+
278
+ <pre class="code ruby"><code class="ruby"><span class='lbrace'>{</span>
279
+ <span class='label'>type:</span> <span class='symbol'>:hash</span><span class='comma'>,</span>
280
+ <span class='label'>hash:</span> <span class='lbrace'>{</span>
281
+ <span class='label'>category:</span> <span class='lbrace'>{</span> <span class='label'>type:</span> <span class='symbol'>:integer</span><span class='comma'>,</span> <span class='label'>allowed_values:</span> <span class='lbracket'>[</span><span class='int'>1</span><span class='comma'>,</span> <span class='int'>2</span><span class='comma'>,</span> <span class='int'>3</span><span class='rbracket'>]</span> <span class='rbrace'>}</span>
282
+ <span class='rbrace'>}</span>
283
+ <span class='rbrace'>}</span>
284
+ </code></pre>
285
+
286
+ <h2>Shortcuts</h2>
287
+
288
+ <h3>Type shortcut</h3>
289
+
290
+ <p>If you&#39;d just like to define a type for a level but don&#39;t need to supply any
291
+ additional information, you can just skip passing an extra hash and just pass
292
+ the type instead.</p>
293
+
294
+ <p>For example, the following</p>
295
+
296
+ <pre class="code ruby"><code class="ruby"><span class='lbrace'>{</span>
297
+ <span class='label'>type:</span> <span class='symbol'>:array</span><span class='comma'>,</span>
298
+ <span class='label'>array:</span> <span class='lbrace'>{</span>
299
+ <span class='label'>type:</span> <span class='symbol'>:string</span>
300
+ <span class='rbrace'>}</span>
301
+ <span class='rbrace'>}</span>
302
+ </code></pre>
303
+
304
+ <p>can also be written as:</p>
305
+
306
+ <pre class="code ruby"><code class="ruby"><span class='lbrace'>{</span>
307
+ <span class='label'>type:</span> <span class='symbol'>:array</span><span class='comma'>,</span>
308
+ <span class='label'>array:</span> <span class='symbol'>:string</span>
309
+ <span class='rbrace'>}</span>
310
+ </code></pre>
311
+
312
+ <h3>Quick hash and array</h3>
313
+
314
+ <p>When specifying a level as hash or array and you&#39;re further specifying the
315
+ hashe&#39;s fields or the array&#39;s content types, you can omit the <code>type</code> key.</p>
316
+
317
+ <p>For example, the following</p>
318
+
319
+ <pre class="code ruby"><code class="ruby"><span class='lbrace'>{</span>
320
+ <span class='label'>type:</span> <span class='symbol'>:array</span><span class='comma'>,</span>
321
+ <span class='label'>array:</span> <span class='lbrace'>{</span>
322
+ <span class='label'>type:</span> <span class='symbol'>:string</span>
323
+ <span class='rbrace'>}</span>
324
+ <span class='rbrace'>}</span>
325
+ </code></pre>
326
+
327
+ <p>can also be written as:</p>
328
+
329
+ <pre class="code ruby"><code class="ruby"><span class='lbrace'>{</span>
330
+ <span class='label'>array:</span> <span class='symbol'>:string</span>
331
+ <span class='rbrace'>}</span>
332
+ </code></pre>
333
+
334
+ <h2>Example schema</h2>
335
+
336
+ <pre class="code ruby"><code class="ruby"><span class='lbrace'>{</span>
337
+ <span class='label'>hash:</span> <span class='lbrace'>{</span>
338
+ <span class='label'>id:</span> <span class='lbracket'>[</span><span class='const'>Integer</span><span class='comma'>,</span> <span class='const'>String</span><span class='rbracket'>]</span><span class='comma'>,</span>
339
+ <span class='label'>name:</span> <span class='symbol'>:string</span><span class='comma'>,</span>
340
+ <span class='label'>meta:</span> <span class='lbrace'>{</span>
341
+ <span class='label'>hash:</span> <span class='lbrace'>{</span>
342
+ <span class='label'>groups:</span> <span class='lbrace'>{</span> <span class='label'>array:</span> <span class='symbol'>:integer</span> <span class='rbrace'>}</span><span class='comma'>,</span>
343
+ <span class='label'>birthday:</span> <span class='const'>Date</span><span class='comma'>,</span>
344
+ <span class='label'>comment:</span> <span class='lbrace'>{</span>
345
+ <span class='label'>type:</span> <span class='symbol'>:string</span><span class='comma'>,</span>
346
+ <span class='label'>required:</span> <span class='kw'>false</span><span class='comma'>,</span>
347
+ <span class='label'>null:</span> <span class='kw'>true</span>
348
+ <span class='rbrace'>}</span><span class='comma'>,</span>
349
+ <span class='label'>ar_object:</span> <span class='const'>User</span>
350
+ <span class='rbrace'>}</span>
351
+ <span class='rbrace'>}</span>
352
+ <span class='rbrace'>}</span><span class='comma'>,</span>
353
+ <span class='rbrace'>}</span>
354
+ </code></pre>
355
+
356
+ <h2>Exceptions</h2>
357
+
358
+ <p>Schemacop will throw one of the following checked exceptions:</p>
359
+
360
+ <ul>
361
+ <li><span class='object_link'><a href="Schemacop/Exceptions/InvalidSchema.html" title="Schemacop::Exceptions::InvalidSchema (class)">Schemacop::Exceptions::InvalidSchema</a></span></li>
362
+ </ul>
363
+
364
+ <p>This exception is thrown when the given schema definition format is invalid.</p>
365
+
366
+ <ul>
367
+ <li><span class='object_link'><a href="Schemacop/Exceptions/Validation.html" title="Schemacop::Exceptions::Validation (class)">Schemacop::Exceptions::Validation</a></span></li>
368
+ </ul>
369
+
370
+ <p>This exception is thrown when the given data does not comply with the given
371
+ schema definition.</p>
372
+
373
+ <h2>Known limitations</h2>
374
+
375
+ <ul>
376
+ <li><p>Schemacop does not yet allow cyclic structures with infinite depth.</p></li>
377
+ <li><p>Schemacop aborts when it encounters an error. It is not able to collect a full
378
+ list of multiple errors.</p></li>
379
+ <li><p>Schemacop is not made for validating complex causalities (i.e. field <code>a</code>
380
+ needs to be given only if field <code>b</code> is present).</p></li>
381
+ <li><p>Schemacop does not yet support string regex matching.</p></li>
382
+ </ul>
383
+
384
+ <h2>Contributors</h2>
385
+
386
+ <p>Thanks to <a href="https://github.com/bbatsov/rubocop">Rubocop</a> for great inspiration
387
+ concerning their name and the structure of their README file.</p>
388
+
389
+ <h2>Changelog</h2>
390
+
391
+ <p>Schemacop&#39;s changelog is available <a href="CHANGELOG.md">here</a>.</p>
392
+
393
+ <h2>Copyright</h2>
394
+
395
+ <p>Copyright (c) 2016 Sitrox. See <a href="LICENSE">LICENSE</a> for further details.</p>
396
+ </div></div>
397
+
398
+ <div id="footer">
399
+ Generated on Mon Jun 6 15:58:59 2016 by
400
+ <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
401
+ 0.8.7.6 (ruby-2.0.0).
402
+ </div>
403
+
404
+ </body>
405
+ </html>
@@ -0,0 +1,60 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+ <html>
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
6
+
7
+ <link rel="stylesheet" href="css/full_list.css" type="text/css" media="screen" charset="utf-8" />
8
+
9
+ <link rel="stylesheet" href="css/common.css" type="text/css" media="screen" charset="utf-8" />
10
+
11
+
12
+
13
+ <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
14
+
15
+ <script type="text/javascript" charset="utf-8" src="js/full_list.js"></script>
16
+
17
+
18
+ <title>File List</title>
19
+ <base id="base_target" target="_parent" />
20
+ </head>
21
+ <body>
22
+ <script type="text/javascript" charset="utf-8">
23
+ var hasFrames = false;
24
+ try {
25
+ hasFrames = window.top.frames.main ? true : false;
26
+ } catch (e) { }
27
+ if (hasFrames) {
28
+ document.getElementById('base_target').target = 'main';
29
+ document.body.className = 'frames';
30
+ }
31
+ </script>
32
+ <div id="content">
33
+ <h1 id="full_list_header">File List</h1>
34
+ <div id="nav">
35
+
36
+ <span><a target="_self" href="class_list.html">
37
+ Classes
38
+ </a></span>
39
+
40
+ <span><a target="_self" href="method_list.html">
41
+ Methods
42
+ </a></span>
43
+
44
+ <span><a target="_self" href="file_list.html">
45
+ Files
46
+ </a></span>
47
+
48
+ </div>
49
+ <div id="search">Search: <input type="text" /></div>
50
+
51
+ <ul id="full_list" class="file">
52
+
53
+
54
+ <li class="r1"><span class="object_link"><a href="index.html" title="README">README</a></a></li>
55
+
56
+
57
+ </ul>
58
+ </div>
59
+ </body>
60
+ </html>