custom templates directory
37 | -L, --logfile [file] output log messages to file
38 | -q, --quiet quiet mode
39 | -h, --help output usage information
40 | ```
41 |
42 | ## Multi-page Output
43 |
44 | Moxygen supports the doxygen [groups](http://www.doxygen.nl/manual/grouping.html#modules) syntax for generating multi page documentation. Every [\defgroup](http://www.doxygen.nl/manual/commands.html#cmddefgroup) in your source code will be parsed and output into a separate markdown file, with internal reference updated accordingly.
45 |
46 | Example:
47 |
48 | ```
49 | moxygen --anchors --groups --output api-%s.md /path/to/doxygen/xml
50 | ```
51 |
52 | ## Example
53 |
54 | To get a feel for how Moxygen works you can play with the example which is located in the [example](/example) folder. The example contains:
55 |
56 | * Documented C++ example code
57 | * A `Doxyfile` file (for doxygen 1.8.13)
58 | * Pre-generated XML output in [example/xml](/example/xml)
59 | * Pre-generated output Markdown files in [example/doc](/example/doc)
60 |
61 | To fully build the example, follow these steps (once you've installed `doxygen`. See **Development & Contribution**, below):
62 |
63 | 1. Rebuild the XML: run `doxygen` from within the example folder.
64 | 2. Rebuild the Moxygen output: from within this directory,
65 |
66 | ```
67 | node bin/moxygen.js --groups --pages --anchors --output=example/doc/api-%s.md example/xml
68 | ```
69 |
70 | ## Development & Contribution
71 |
72 | You can develop this project as you would any other Node project:
73 |
74 | 1. Clone this repo.
75 | 2. `npm install` from this directory.
76 |
77 | This project is tested through integration, by building the `example/`. To quickly test this project:
78 |
79 | 1. Install `doxygen` (`brew install doxygen`, `choco install doxygen`, for example). Only must be done once per computer.
80 | 2. `npm test` from this directory. This will run Doxygen on the `example/` and build the output.
81 |
--------------------------------------------------------------------------------
/src/helpers.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Original work Copyright (c) 2016 Philippe FERDINAND
3 | * Modified work Copyright (c) 2016 Kam Low
4 | *
5 | * @license MIT
6 | **/
7 | 'use strict';
8 |
9 | var fs = require('fs');
10 | var path = require('path');
11 | var util = require('util');
12 | var log = require('./logger').getLogger();
13 | var handlebars = require('handlebars');
14 |
15 | module.exports = {
16 |
17 | inline: function(code) {
18 | if (Array.isArray(code)) {
19 | var refs, s = '', isInline = false;
20 | code.forEach(function (e) {
21 | refs = e.split(/(\[.*\]\(.*\)|\n|\s{2}\n)/g);
22 | refs.forEach(function (f) {
23 | if (f.charAt(0) == '[') {
24 | // link
25 | var link = f.match(/\[(.*)\]\((.*)\)/);
26 | if (link) {
27 | isInline ? (s += '`') && (isInline = false) : null;
28 | s += '[`' + link[1] + '`](' + link[2] + ')';
29 | }
30 | }
31 | else if (f == '\n' || f == ' \n') {
32 | // line break
33 | isInline ? (s += '`') && (isInline = false) : null;
34 | s += f;
35 | }
36 | else if (f) {
37 | !isInline ? (s += '`') && (isInline = true) : null;
38 | s += f;
39 | }
40 | });
41 | });
42 | return s + (isInline ? '`' : '');
43 | }
44 | else {
45 | return '`' + code + '`';
46 | }
47 | },
48 |
49 | getAnchor: function(name, options) {
50 | if (options.anchors) {
51 | return '{#' + name + '}';
52 | }
53 | else if (options.htmlAnchors) {
54 | return '';
55 | }
56 | else {
57 | return '';
58 | }
59 | },
60 |
61 | findParent: function(compound, kinds) {
62 | while (compound) {
63 | if (kinds.includes(compound.kind))
64 | return compound;
65 | compound = compound.parent;
66 | }
67 | },
68 |
69 | // Replace ref links to point to correct output file if needed
70 | resolveRefs: function(content, compound, references, options) {
71 | return content.replace(/\{#ref ([^ ]+) #\}/g, function(_, refid) {
72 | var ref = references[refid]
73 | var page = this.findParent(ref, ['page']);
74 |
75 | if (page) {
76 | if (page.refid == compound.refid)
77 | return '#' + refid;
78 | return this.compoundPath(page, options) + '#' + refid;
79 | }
80 |
81 | if (options.groups) {
82 | if (compound.groupid && compound.groupid == ref.groupid)
83 | return '#' + refid;
84 | return this.compoundPath(ref, options) + '#' + refid;
85 | } else if (options.classes) {
86 | var dest = this.findParent(ref, ['namespace', 'class', 'struct']);
87 | if (!dest || compound.refid == dest.refid)
88 | return '#' + refid;
89 | return this.compoundPath(dest, options) + '#' + refid;
90 | } else {
91 | if (compound.kind == 'page')
92 | return this.compoundPath(compound.parent, options) + '#' + refid;
93 | return '#' + refid;
94 | }
95 | }.bind(this));
96 | },
97 |
98 | compoundPath: function(compound, options) {
99 | if (compound.kind == 'page') {
100 | return path.dirname(options.output) + "/page-" + compound.name + ".md";
101 | } else if (options.groups) {
102 | return util.format(options.output, compound.groupname);
103 | } else if (options.classes) {
104 | return util.format(options.output, compound.name.replace(/\:/g, '-').replace('<', '(').replace('>', ')'));
105 | } else {
106 | return options.output;
107 | }
108 | },
109 |
110 | writeCompound: function(compound, contents, references, options) {
111 | this.writeFile(this.compoundPath(compound, options), contents.map(function(content) {
112 | return this.resolveRefs(content, compound, references, options);
113 | }.bind(this)));
114 | },
115 |
116 | // Write the output file
117 | writeFile: function (filepath, contents) {
118 | log.verbose('Writing: ' + filepath);
119 | var stream = fs.createWriteStream(filepath);
120 | stream.once('open', function(fd) {
121 | contents.forEach(function (content) {
122 | if (content)
123 | stream.write(content);
124 | });
125 | stream.end();
126 | });
127 | },
128 | };
129 |
--------------------------------------------------------------------------------
/example/xml/classtransport_1_1RacingBike.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | transport::RacingBike
5 | transport::Bicycle
6 | racingbike.h
7 |
8 |
9 | void
10 | void RacingBike::PedalHarder
11 | ()
12 | PedalHarder
13 | PedalHarder
14 |
15 | PedalHarder makes you go faster (usually).
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | void
24 | void RacingBike::RingBell
25 | ()
26 | RingBell
27 | RingBell
28 |
29 |
30 |
31 | Ring bell on the bike.RingBell rings the bell on the bike. Note that not all bikes have bells.
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | Racing bike class.[RacingBike] is a special kind of bike which can go much faster on the road, with much less effort (even uphill!). It doesn't make sense to call RingBell on a racing bike for they don't have bells.
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | transport::RacingBikePedalHarder
68 | transport::RacingBikeRingBell
69 | transport::RacingBike~Bicycle
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/example/xml/racingbike_8h.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | racingbike.h
5 | transport/bicycle.h
6 | src/racingbike.cpp
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | transport::RacingBike
19 | transport
20 |
21 |
22 |
23 |
24 |
25 | #ifndef__TRANSPORT_RACING_BIKE_H__
26 | #define__TRANSPORT_RACING_BIKE_H__
27 |
28 | #include<transport/bicycle.h>
29 |
30 | namespace[transport]
31 | {
32 | class[RacingBike]:public[Bicycle]
33 | {
34 | public:
35 |
36 | virtualvoid[PedalHarder]();
37 |
38 |
39 | virtualvoid[RingBell]();
40 | };
41 | }
42 |
43 | #endif
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/example/xml/classtransport_1_1Bicycle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | transport::Bicycle
5 | transport::MountainBike
6 | transport::RacingBike
7 | bicycle.h
8 |
9 |
10 | void
11 | void Bicycle::PedalHarder
12 | ()
13 | PedalHarder
14 | PedalHarder
15 |
16 | PedalHarder makes you go faster (usually).
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | void
25 | void Bicycle::RingBell
26 | ()
27 | RingBell
28 | RingBell
29 |
30 |
31 |
32 | Ring bell on the bike.RingBell rings the bell on the bike. Note that not all bikes have bells.
33 |
34 |
35 |
36 |
37 |
38 |
39 | Bicycle::~Bicycle
40 | ()
41 | ~Bicycle
42 |
43 | Default destructor.
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | Standard bicycle class.[Bicycle] implements a standard bicycle. Bicycles are a useful way of transporting oneself, without too much effort (unless you go uphill or against the wind). If there are a lot of people on the road, you can use RingBell to ring your bell (note, not all bicycles have bells!).
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | transport::BicyclePedalHarder
76 | transport::BicycleRingBell
77 | transport::Bicycle~Bicycle
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Original work Copyright (c) 2016 Philippe FERDINAND
3 | * Modified work Copyright (c) 2016 Kam Low
4 | *
5 | * @license MIT
6 | **/
7 | 'use strict';
8 |
9 | var path = require('path');
10 |
11 | var doxyparser = require('./src/parser');
12 | var templates = require('./src/templates');
13 | var helpers = require('./src/helpers');
14 |
15 | module.exports = {
16 |
17 | /**
18 | * Default options values.
19 | **/
20 | defaultOptions: {
21 |
22 | directory: null, /** Location of the doxygen files **/
23 | output: 'api.md', /** Output file **/
24 | groups: false, /** Output doxygen groups separately **/
25 | noindex: false, /** Disable generation of the index. Does not work with `groups` option **/
26 | anchors: true, /** Generate anchors for internal links **/
27 | language: 'cpp', /** Programming language **/
28 | templates: 'templates', /** Templates directory **/
29 | pages: false, /** Output doxygen pages separately **/
30 | classes: false, /** Output doxygen classes separately **/
31 | output_s: 'api_%s.md', /** Output file for groups and classes **/
32 | logfile: 'moxygen.log', /** Log file **/
33 |
34 | filters: {
35 | members: [
36 | 'define',
37 | 'enum',
38 | // 'enumvalue',
39 | 'func',
40 | // 'variable',
41 | 'property',
42 | 'public-attrib',
43 | 'public-func',
44 | 'protected-attrib',
45 | 'protected-func',
46 | 'signal',
47 | 'public-slot',
48 | 'protected-slot',
49 | 'public-type',
50 | 'private-attrib',
51 | 'private-func',
52 | 'private-slot',
53 | 'public-static-func',
54 | 'private-static-func',
55 | ],
56 | compounds: [
57 | 'namespace',
58 | 'class',
59 | 'struct',
60 | 'union',
61 | 'typedef',
62 | 'interface',
63 | // 'file',
64 | ]
65 | },
66 | },
67 |
68 | /**
69 | * Parse files and render the output.
70 | **/
71 | run: function (options) {
72 |
73 | // Sanitize options
74 | if (typeof options.output == "undefined") {
75 | if (options.classes || options.groups) {
76 | options.output = this.defaultOptions.output_s;
77 | }
78 | else {
79 | options.output = this.defaultOptions.output;
80 | }
81 | }
82 |
83 | if ((options.classes || options.groups) && options.output.indexOf('%s') === -1) {
84 | throw "The `output` file parameter must contain an '%s' for group or class name " +
85 | "substitution when `groups` or `classes` are enabled."
86 | }
87 |
88 | if (typeof options.templates == "undefined") {
89 | options.templates = path.join(__dirname, this.defaultOptions.templates, options.language);
90 | }
91 |
92 | // Load templates
93 | templates.registerHelpers(options);
94 | templates.load(options.templates);
95 |
96 | // Parse files
97 | doxyparser.loadIndex(options, function (err, root) {
98 | if (err)
99 | throw err;
100 | // Output groups
101 | if (options.groups) {
102 | var groups = root.toArray('compounds', 'group');
103 | if (!groups.length)
104 | throw "You have enabled `groups` output, but no groups were " +
105 | "located in your doxygen XML files."
106 |
107 | groups.forEach(function (group) {
108 | group.filterChildren(options.filters, group.id);
109 |
110 | var compounds = group.toFilteredArray('compounds');
111 | compounds.unshift(group); // insert group at top
112 | helpers.writeCompound(group, templates.renderArray(compounds), doxyparser.references, options);
113 | });
114 | }
115 | else if (options.classes) {
116 | var rootCompounds = root.toArray('compounds', 'namespace');
117 | if (!rootCompounds.length)
118 | throw "You have enabled `classes` output, but no classes were " +
119 | "located in your doxygen XML files."
120 | rootCompounds.forEach(function (comp) {
121 | comp.filterChildren(options.filters);
122 | var compounds = comp.toFilteredArray();
123 | helpers.writeCompound(comp, [templates.render(comp)], doxyparser.references, options);
124 | compounds.forEach(function (e) {
125 | e.filterChildren(options.filters)
126 | helpers.writeCompound(e, [templates.render(e)], doxyparser.references, options);
127 | });
128 | });
129 | }
130 | // Output single file
131 | else {
132 | root.filterChildren(options.filters);
133 |
134 | var compounds = root.toFilteredArray('compounds');
135 | if (!options.noindex)
136 | compounds.unshift(root); // insert root at top if index is enabled
137 | var contents = templates.renderArray(compounds);
138 | contents.push('Generated by [Moxygen](https://sourcey.com/moxygen)')
139 | helpers.writeCompound(root, contents, doxyparser.references, options);
140 | }
141 |
142 | if(options.pages){
143 | var pages = root.toArray('compounds', 'page');
144 | if(!pages.length)
145 | throw "You have enabled `pages` output, but no pages were " +
146 | "located in your doxygen XML files."
147 | pages.forEach(function(page){
148 | var compounds = page.toFilteredArray('compounds');
149 | compounds.unshift(page);
150 | helpers.writeCompound(page, templates.renderArray(compounds), doxyparser.references, options);
151 | })
152 | }
153 |
154 | });
155 | },
156 | }
157 |
--------------------------------------------------------------------------------
/example/xml/classtransport_1_1MountainBike.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | transport::MountainBike
5 | transport::Bicycle
6 | mountainbike.h
7 |
8 |
9 | bool
10 | bool MountainBike::SetSuspension
11 | (double stiffness)
12 | SetSuspension
13 |
14 | double
15 | stiffness
16 |
17 |
18 |
19 |
20 | Set suspension stiffness. the suspension stiffness.SetSuspension changes the stiffness of the suspension on the bike. The method will return false if the stiffness could not be adjusted.true if the suspension was adjusted successfully, false otherwise.
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | typename BreakType
30 |
31 |
32 | bool
33 | bool transport::MountainBike::ChangeBreak
34 | (BreakType breakType)
35 | ChangeBreak
36 |
37 | BreakType
38 | breakType
39 |
40 |
41 |
42 |
43 | Change the break type. the break type. the type of the break.ChangesBreak changes the type of break fitted to the bike. The method will return false if the break type could not be fitted.true if the break was adjusted successfully. false otherise
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | Mountain bike implementation of a [Bicycle].[MountainBike] is an implementation of a [Bicycle] providing a bike for cycling on rough terrain. Mountain bikes are pretty cool because they have stuff like Suspension (and you can even adjust it using SetSuspension). If you're looking for a bike for use on the road, you might be better off using a [RacingBike] though.
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | transport::MountainBikeChangeBreak
81 | transport::MountainBikePedalHarder
82 | transport::MountainBikeRingBell
83 | transport::MountainBikeSetSuspension
84 | transport::MountainBike~Bicycle
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/example/xml/mountainbike_8h.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | mountainbike.h
5 | transport/bicycle.h
6 | src/mountainbike.cpp
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | transport::MountainBike
19 | transport
20 |
21 |
22 |
23 |
24 |
25 | #ifndef__TRANSPORT_MOUNTAIN_BIKE_H__
26 | #define__TRANSPORT_MOUNTAIN_BIKE_H__
27 |
28 | #include<transport/bicycle.h>
29 |
30 | namespace[transport]
31 | {
32 | class[MountainBike]:public[Bicycle]
33 | {
34 | public:
35 | bool[SetSuspension](doublestiffness);
36 |
37 | template<typenameBreakType>
38 | bool[ChangeBreak](BreakTypebreakType)
39 | {
40 | if(breakType)
41 | {
42 | returntrue;
43 | }
44 |
45 | returnfalse;
46 | }
47 | };
48 | }
49 |
50 | #endif
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/example/xml/transport_8h.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | transport.h
5 | transport/bicycle.h
6 | transport/racingbike.h
7 | transport/mountainbike.h
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | PEDAL_POWER_MODIFIER
32 | 9000
33 |
34 |
35 |
36 | The modifier value if pedal power is used.This definition exists in the default namespace and is ungrouped. It will not be displayed if the groups options is used.
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | TransportType
46 |
47 | Bycicle
48 |
49 |
50 |
51 | Bycicle type
52 |
53 |
54 | RacingBike
55 |
56 |
57 |
58 | Racing bike type
59 |
60 |
61 | RacingBike
62 |
63 |
64 |
65 | Mountain bike type
66 |
67 |
68 |
69 |
70 | Enum class for transport types.This definition exists in the default namespace and is ungrouped. It will not be displayed if the groups options is used.
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 | #ifndef__TRANSPORT_H__
82 | #define__TRANSPORT_H__
83 |
84 | #include<transport/bicycle.h>
85 |
86 | #include<transport/racingbike.h>
87 |
88 | #include<transport/mountainbike.h>
89 |
90 | enumclassTransportType{
91 | Bycicle,
92 | RacingBike,
93 | RacingBike
94 | };
95 |
96 | #definePEDAL_POWER_MODIFIER9000
97 |
98 | #endif
99 |
100 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/src/parser.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Original work Copyright (c) 2016 Philippe FERDINAND
3 | * Modified work Copyright (c) 2016 Kam Low
4 | *
5 | * @license MIT
6 | **/
7 | 'use strict';
8 |
9 | var fs = require('fs');
10 | var log = require('./logger').getLogger();
11 | var path = require('path');
12 | var xml2js = require('xml2js');
13 |
14 | var Compound = require('./compound');
15 | var helpers = require('./helpers');
16 | var markdown = require('./markdown');
17 |
18 | function toMarkdown(element, context) {
19 | var s = '';
20 | context = context || [];
21 | switch (typeof element) {
22 | case 'string':
23 | s = element;
24 | break;
25 |
26 | case 'object':
27 | if (Array.isArray(element)) {
28 | element.forEach(function (value, key) {
29 | s += toMarkdown(value, context);
30 | });
31 | }
32 | else {
33 |
34 | // opening the element
35 | switch (element['#name']) {
36 | case 'ref': return s + markdown.refLink(toMarkdown(element.$$), element.$.refid);
37 | case '__text__': s = element._; break;
38 | case 'emphasis': s = '*'; break;
39 | case 'bold': s = '**'; break;
40 | case 'parametername':
41 | case 'computeroutput': s = '`'; break;
42 | case 'parameterlist':
43 | if (element.$.kind == 'exception') {
44 | s = '\n#### Exceptions\n'
45 | }
46 | else {
47 | s = '\n#### Parameters\n'
48 | }
49 | break;
50 |
51 | case 'parameteritem': s = '* '; break;
52 | case 'programlisting': s = '\n```cpp\n'; break;
53 | case 'orderedlist':
54 | context.push(element);
55 | s = '\n\n';
56 | break;
57 | case 'itemizedlist': s = '\n\n'; break;
58 | case 'listitem':
59 | s = (context.length > 0 && context[context.length - 1]['#name'] == 'orderedlist') ? '1. ' : '* ';
60 | break;
61 | case 'sp': s = ' '; break;
62 | case 'heading': s = '## '; break;
63 | case 'xrefsect': s += '\n> '; break;
64 | case 'simplesect':
65 | if (element.$.kind == 'attention') {
66 | s = '> ';
67 | }
68 | else if (element.$.kind == 'return') {
69 | s = '\n#### Returns\n'
70 | }
71 | else if (element.$.kind == 'see') {
72 | s = '**See also**: '
73 | }
74 | else {
75 | console.assert(element.$.kind + ' not supported.');
76 | }
77 | break;
78 | case 'formula':
79 | s = trim(element._);
80 | if (s.startsWith('$') && s.endsWith('$')) return s;
81 | if (s.startsWith('\\[') && s.endsWith('\\]'))
82 | s = trim(s.substring(2, s.length - 2));
83 | return '\n$$\n' + s + '\n$$\n';
84 | case 'preformatted': s = '\n'; break;
85 |
86 | case 'sect1':
87 | case 'sect2':
88 | case 'sect3':
89 | context.push(element);
90 | s = '\n' + helpers.getAnchor(element.$.id, module.exports.parserOptions) + '\n';
91 | break;
92 | case 'title':
93 | var level = '#'.repeat(context[context.length - 1]['#name'].slice(-1));
94 | s = '\n#' + level + ' ' + element._ + '\n';
95 | break;
96 |
97 | case 'mdash': s = '—'; break;
98 | case 'ndash': s = '–'; break;
99 | case 'linebreak': s = '
'; break;
100 |
101 | case 'xreftitle':
102 | case 'entry':
103 | case 'row':
104 | case 'ulink':
105 | case 'codeline':
106 | case 'highlight':
107 | case 'table':
108 | case 'para':
109 | case 'parameterdescription':
110 | case 'parameternamelist':
111 | case 'xrefdescription':
112 | case 'verbatim':
113 | case 'hruler':
114 | case undefined:
115 | break;
116 |
117 | default:
118 | console.error(false, element['#name'] + ': not yet supported.');
119 | }
120 |
121 | // recurse on children elements
122 | if (element.$$) {
123 | s += toMarkdown(element.$$, context);
124 | }
125 |
126 | // closing the element
127 | switch (element['#name']) {
128 | case 'parameterlist':
129 | case 'para': s += '\n\n'; break;
130 | case 'emphasis': s += '*'; break;
131 | case 'bold': s += '**'; break;
132 | case 'parameteritem': s += '\n'; break;
133 | case "computeroutput": s += '`'; break;
134 | case 'parametername': s += '` '; break;
135 | case 'entry': s = markdown.escape.cell(s) + '|'; break;
136 | case 'programlisting': s += '```\n'; break;
137 | case 'codeline': s += '\n'; break;
138 | case 'ulink': s = markdown.link(s, element.$.url); break;
139 | case 'orderedlist':
140 | context.pop();
141 | s += '\n';
142 | break;
143 | case 'itemizedlist': s += '\n'; break;
144 | case 'listitem': s += '\n'; break;
145 | case 'entry': s = ' | '; break;
146 | case 'xreftitle': s += ': '; break;
147 | case 'preformatted': s += '
\n'; break;
148 | case 'sect1':
149 | case 'sect2':
150 | case 'sect3':
151 | context.pop();
152 | s += '\n';
153 | break;
154 | case 'row':
155 | s = '\n' + markdown.escape.row(s);
156 | if (element.$$ && element.$$[0].$.thead == "yes") {
157 | element.$$.forEach(function (th, i) {
158 | s += (i ? ' | ' : '\n') + '---------';
159 | });
160 | }
161 | break;
162 | }
163 |
164 | }
165 | break;
166 |
167 | default:
168 | console.assert(false);
169 | }
170 |
171 | return s;
172 | }
173 |
174 | function trim(text) {
175 | return text.replace(/^[\s\t\r\n]+|[\s\t\r\n]+$/g, '');
176 | }
177 |
178 | function copy(dest, property, def) {
179 | dest[property] = trim(toMarkdown(def[property]));
180 | }
181 |
182 | function summary(dest, def) {
183 | // set from briefdescription or first paragraph of detaileddescription
184 | var summary = trim(toMarkdown(def['briefdescription']));
185 | if (!summary) {
186 | summary = trim(toMarkdown(def['detaileddescription']));
187 | if (summary) {
188 | var firstSentence = summary.split('\n', 1)[0]; //.split('. ').first;
189 | if (firstSentence)
190 | summary = firstSentence;
191 | }
192 | }
193 | dest['summary'] = summary;
194 | }
195 |
196 | module.exports = {
197 |
198 | // All references indexed by refid
199 | references: {},
200 |
201 | // The root compound
202 | root: new Compound(),
203 |
204 | parseMembers: function (compound, props, membersdef) {
205 |
206 | // copy all properties
207 | Object.keys(props).forEach(function(prop) {
208 | compound[prop] = props[prop];
209 | });
210 |
211 | this.references[compound.refid] = compound;
212 |
213 | if (membersdef) {
214 | membersdef.forEach(function (memberdef) {
215 | var member = { name: memberdef.name[0], parent: compound };
216 | compound.members.push(member);
217 | Object.keys(memberdef.$).forEach(function(prop) {
218 | member[prop] = memberdef.$[prop];
219 | });
220 | this.references[member.refid] = member;
221 | }.bind(this));
222 | }
223 | },
224 |
225 | parseMember: function (member, section, memberdef) {
226 | log.verbose('Processing member ' + member.kind + ' ' + member.name);
227 | member.section = section;
228 | copy(member, 'briefdescription', memberdef);
229 | copy(member, 'detaileddescription', memberdef);
230 | summary(member, memberdef);
231 |
232 | var m = [];
233 | switch (member.kind) {
234 | case 'signal':
235 | case 'slot':
236 | m = m.concat(['{', member.kind, '} ']);
237 |
238 | case 'function':
239 | m = m.concat(memberdef.$.prot, ' '); // public, private, ...
240 | if (memberdef.templateparamlist) {
241 | m.push('template<');
242 | if (memberdef.templateparamlist.length > 0 && memberdef.templateparamlist.param) {
243 | memberdef.templateparamlist[0].param.forEach(function (param, argn) {
244 | m = m.concat(argn == 0 ? [] : ',');
245 | m = m.concat([toMarkdown(param.type)]);
246 | m = m.concat(param.declname ? [' ', toMarkdown(param.declname)] : []);
247 | });
248 | }
249 | m.push('> \n');
250 | }
251 | m = m.concat(memberdef.$.inline == 'yes' ? ['inline', ' '] : []);
252 | m = m.concat(memberdef.$.static == 'yes' ? ['static', ' '] : []);
253 | m = m.concat(memberdef.$.virt == 'virtual' ? ['virtual', ' '] : []);
254 | m = m.concat(toMarkdown(memberdef.type), ' ');
255 | m = m.concat(memberdef.$.explicit == 'yes' ? ['explicit', ' '] : []);
256 | // m = m.concat(memberdef.name[0]._);
257 | m = m.concat(markdown.refLink(member.name, member.refid));
258 | m = m.concat('(');
259 | if (memberdef.param) {
260 | memberdef.param.forEach(function (param, argn) {
261 | m = m.concat(argn == 0 ? [] : ', ');
262 | m = m.concat([toMarkdown(param.type)]);
263 | m = m.concat(param.declname ? [' ', toMarkdown(param.declname)] : []);
264 | });
265 | }
266 |
267 | m = m.concat(')');
268 | m = m.concat(memberdef.$['const'] == 'yes' ? [' ', 'const'] : []);
269 | m = m.concat(memberdef.argsstring[0]._.match(/noexcept$/) ? ' noexcept' : '');
270 | m = m.concat(memberdef.argsstring[0]._.match(/=\s*delete$/) ? ' = delete' : '');
271 | m = m.concat(memberdef.argsstring[0]._.match(/=\s*default/) ? ' = default' : '');
272 | break;
273 |
274 | case 'variable':
275 | m = m.concat(memberdef.$.prot, ' '); // public, private, ...
276 | m = m.concat(memberdef.$.static == 'yes' ? ['static', ' '] : []);
277 | m = m.concat(memberdef.$.mutable == 'yes' ? ['mutable', ' '] : []);
278 | m = m.concat(toMarkdown(memberdef.type), ' ');
279 | // m = m.concat(memberdef.name[0]._);
280 | m = m.concat(markdown.refLink(member.name, member.refid));
281 | break;
282 |
283 | case 'property':
284 | m = m.concat(['{', member.kind, '} ']);
285 | m = m.concat(toMarkdown(memberdef.type), ' ');
286 | // m = m.concat(memberdef.name[0]._);
287 | m = m.concat(markdown.refLink(member.name, member.refid));
288 | break;
289 |
290 | case 'enum':
291 | member.enumvalue = [];
292 | if (memberdef.enumvalue) {
293 | memberdef.enumvalue.forEach(function (param, argn) {
294 | var enumvalue = {}
295 | copy(enumvalue, 'name', param);
296 | copy(enumvalue, 'briefdescription', param);
297 | copy(enumvalue, 'detaileddescription', param);
298 | summary(enumvalue, param);
299 | member.enumvalue.push(enumvalue);
300 | });
301 | }
302 | // m.push(member.kind + ' ' + member.name);
303 | m = m.concat([member.kind, ' ', markdown.refLink(member.name, member.refid)]);
304 | break;
305 |
306 | default:
307 | // m.push(member.kind + ' ' + member.name);
308 | m = m.concat([member.kind, ' ', markdown.refLink(member.name, member.refid)]);
309 | break;
310 | }
311 |
312 | member.proto = helpers.inline(m);
313 | },
314 |
315 | assignToNamespace: function (compound, child) {
316 | if (compound.name != child.namespace)
317 | console.assert('namespace mismatch: ', compound.name, '!=', child.namespace);
318 |
319 | // namespaces take ownership of the child compound
320 | if (child.parent)
321 | delete child.parent.compounds[child.id];
322 | compound.compounds[child.id] = child;
323 | child.parent = compound;
324 | },
325 |
326 | assignNamespaceToGroup: function (compound, child) {
327 |
328 | // add the namespace to the group
329 | compound.compounds[child.id] = child;
330 |
331 | // remove namespace clildren from direct group children
332 | Object.keys(child.compounds).forEach(function(id) {
333 | delete compound.compounds[id];
334 | });
335 | },
336 |
337 | assignClassToGroup: function (compound, child) {
338 |
339 | // add the namespace to the group
340 | // if the child already belongs to a child namespace it will be removed
341 | // on the call to `assignNamespaceToGroup`
342 | compound.compounds[child.id] = child;
343 |
344 | // add a groupid and reference to the compound and all it's members
345 | child.groupid = compound.id;
346 | child.groupname = compound.name;
347 |
348 | child.members.forEach(function (member) {
349 | member.groupid = compound.id;
350 | member.groupname = compound.name;
351 | });
352 | },
353 |
354 | extractPageSections: function(page, elements) {
355 | elements.forEach(function(element) {
356 | if (element['#name'] == 'sect1' || element['#name'] == 'sect2' || element['#name'] == 'sect3') {
357 | var id = element.$.id;
358 | var member = { section: element['#name'], id: id, name: id, refid: id, parent: page };
359 | page.members.push(member);
360 | this.references[member.refid] = member;
361 | }
362 | if (element.$$)
363 | this.extractPageSections(page, element.$$);
364 | }.bind(this));
365 | },
366 |
367 | parseCompound: function (compound, compounddef) {
368 | log.verbose('Processing compound ' + compound.name);
369 | Object.keys(compounddef.$).forEach(function(prop) {
370 | compound[prop] = compounddef.$[prop];
371 | });
372 | compound.fullname = compounddef.compoundname[0]._;
373 | copy(compound, 'briefdescription', compounddef);
374 | copy(compound, 'detaileddescription', compounddef);
375 | summary(compound, compounddef);
376 |
377 | if (compounddef.basecompoundref) {
378 | compounddef.basecompoundref.forEach(function (basecompoundref) {
379 | compound.basecompoundref.push({
380 | prot: basecompoundref.$.prot,
381 | name: basecompoundref._,
382 | });
383 | });
384 | }
385 |
386 | if (compounddef.sectiondef) {
387 | compounddef.sectiondef.forEach(function (section) {
388 | // switch (section.$['kind']) {
389 | // case 'define':
390 | // case 'enum':
391 | // case 'friend':
392 | // case 'public-attrib':
393 | // case 'public-func':
394 | // case 'protected-attrib':
395 | // case 'protected-func':
396 | // case 'private-attrib':
397 | // case 'private-func':
398 | if (section.memberdef) {
399 | section.memberdef.forEach(function (memberdef) {
400 | var member = this.references[memberdef.$.id];
401 |
402 | if (compound.kind == 'group') {
403 | member.groupid = compound.id;
404 | member.groupname = compound.name;
405 | }
406 | else if (compound.kind == 'file') {
407 | // add free members defined inside files in the default
408 | // namespace to the root compound
409 | this.root.members.push(member);
410 | }
411 | this.parseMember(member, section.$['kind'], memberdef);
412 | }.bind(this));
413 | }
414 | // break;
415 | //
416 | // default:
417 | // console.assert(true);
418 | // }
419 | }.bind(this));
420 | }
421 |
422 | compound.proto = helpers.inline([compound.kind, ' ', markdown.refLink(compound.name, compound.refid)]);
423 |
424 | // kind specific parsing
425 | switch (compound.kind) {
426 | case 'class':
427 | case 'struct':
428 | case 'union':
429 | case 'typedef':
430 |
431 | // set namespace reference
432 | var nsp = compound.name.split('::');
433 | compound.namespace = nsp.splice(0, nsp.length - 1).join('::');
434 | break;
435 |
436 | case 'file':
437 | // NOTE: to handle free functions in the default namespace we would
438 | // parse add all contained members to the root compound.
439 | break;
440 |
441 | case 'page':
442 | this.extractPageSections(compound, compounddef.$$);
443 | break;
444 |
445 | case 'namespace':
446 | case 'group':
447 |
448 | if (compound.kind == 'group') {
449 | compound.groupid = compound.id;
450 | compound.groupname = compound.name;
451 | }
452 |
453 | // handle innerclass for groups and namespaces
454 | if (compounddef.innerclass) {
455 | compounddef.innerclass.forEach(function (innerclassdef) {
456 | if (compound.kind == 'namespace') {
457 | // log.verbose('Assign ' + innerclassdef.$.refid + ' to namespace ' + compound.name);
458 |
459 | if (this.references[innerclassdef.$.refid])
460 | this.assignToNamespace(compound, this.references[innerclassdef.$.refid]);
461 | }
462 | else if (compound.kind == 'group') {
463 | // log.verbose('Assign ' + innerclassdef.$.refid + ' to group ' + compound.name);
464 | if (this.references[innerclassdef.$.refid])
465 | this.assignClassToGroup(compound, this.references[innerclassdef.$.refid]);
466 | }
467 | }.bind(this));
468 | }
469 |
470 | // handle innernamespace for groups and namespaces
471 | if (compounddef.innernamespace) {
472 | compound.innernamespaces = [];
473 | compounddef.innernamespace.forEach(function (namespacedef) {
474 | if (compound.kind == 'group') {
475 | // log.verbose('Assign namespace ' + namespacedef.$.refid + ' to group ' + compound.name);
476 | this.assignNamespaceToGroup(compound, this.references[namespacedef.$.refid]);
477 | }
478 | }.bind(this));
479 | }
480 | break;
481 | default:
482 | console.assert(true);
483 | }
484 |
485 | return;
486 | },
487 |
488 | parseIndex: function (root, index, options) {
489 | index.forEach(function (element) {
490 | var doxygen, compound = root.find(element.$.refid, element.name[0], true);
491 | var xmlParser = new xml2js.Parser({
492 | explicitChildren: true,
493 | preserveChildrenOrder: true,
494 | charsAsChildren: true
495 | });
496 |
497 | this.parseMembers(compound, element.$, element.member);
498 |
499 | if (compound.kind !== 'file') { // && compound.kind !== 'file'
500 | log.verbose('Parsing ' + path.join(options.directory, compound.refid + '.xml'));
501 | doxygen = fs.readFileSync(path.join(options.directory, compound.refid + '.xml'), 'utf8');
502 | xmlParser.parseString(doxygen, function (err, data) {
503 | if (err) {
504 | log.verbose('warning - parse error for file: ' + path.join(options.directory, compound.refid + '.xml'))
505 | return;
506 | }
507 | this.parseCompound(compound, data.doxygen.compounddef[0]);
508 | }.bind(this));
509 | }
510 |
511 | }.bind(this));
512 | },
513 |
514 | loadIndex: function (options, callback) {
515 | this.parserOptions = options;
516 | log.verbose('Parsing ' + path.join(options.directory, 'index.xml'));
517 | fs.readFile(path.join(options.directory, 'index.xml'), 'utf8', function(err, data) {
518 | if (err) {
519 | callback('Failed to load doxygen XML: ' + err);
520 | return;
521 | }
522 | var xmlParser = new xml2js.Parser();
523 | xmlParser.parseString(data, function (err, result) {
524 | if (err) {
525 | callback('Failed to parse doxygen XML: ' + err);
526 | return;
527 | }
528 | this.root.kind = 'index';
529 | this.parseIndex(this.root, result.doxygenindex.compound, options);
530 | callback(null, this.root); // TODO: return errors properly
531 | }.bind(this));
532 | }.bind(this));
533 | },
534 | };
535 |
--------------------------------------------------------------------------------
/example/xml/compound.xsd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |
488 |
489 |
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 |
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 |
540 |
541 |
542 |
543 |
544 |
545 |
546 |
547 |
548 |
549 |
550 |
551 |
552 |
553 |
554 |
555 |
556 |
557 |
558 |
559 |
560 |
561 |
562 |
563 |
564 |
565 |
566 |
567 |
568 |
569 |
570 |
571 |
572 |
573 |
574 |
575 |
576 |
577 |
578 |
579 |
580 |
581 |
582 |
583 |
584 |
585 |
586 |
587 |
588 |
589 |
590 |
591 |
592 |
593 |
594 |
595 |
596 |
597 |
598 |
599 |
600 |
601 |
602 |
603 |
604 |
605 |
606 |
607 |
608 |
609 |
610 |
611 |
612 |
613 |
614 |
615 |
616 |
617 |
618 |
619 |
620 |
621 |
622 |
623 |
624 |
625 |
626 |
627 |
628 |
629 |
630 |
631 |
632 |
633 |
634 |
635 |
636 |
637 |
638 |
639 |
640 |
641 |
642 |
643 |
644 |
645 |
646 |
647 |
648 |
649 |
650 |
651 |
652 |
653 |
654 |
655 |
656 |
657 |
658 |
659 |
660 |
661 |
662 |
663 |
664 |
665 |
666 |
667 |
668 |
669 |
670 |
671 |
672 |
673 |
674 |
675 |
676 |
677 |
678 |
679 |
680 |
681 |
682 |
683 |
684 |
685 |
686 |
687 |
688 |
689 |
690 |
691 |
692 |
693 |
694 |
695 |
696 |
697 |
698 |
699 |
700 |
701 |
702 |
703 |
704 |
705 |
706 |
707 |
708 |
709 |
710 |
711 |
712 |
713 |
714 |
715 |
716 |
717 |
718 |
719 |
720 |
721 |
722 |
723 |
724 |
725 |
726 |
727 |
728 |
729 |
730 |
731 |
732 |
733 |
734 |
735 |
736 |
737 |
738 |
739 |
740 |
741 |
742 |
743 |
744 |
745 |
746 |
747 |
748 |
749 |
750 |
751 |
752 |
753 |
754 |
755 |
756 |
757 |
758 |
759 |
760 |
761 |
762 |
763 |
764 |
765 |
766 |
767 |
768 |
769 |
770 |
771 |
772 |
773 |
774 |
775 |
776 |
777 |
778 |
779 |
780 |
781 |
782 |
783 |
784 |
785 |
786 |
787 |
788 |
789 |
790 |
791 |
792 |
793 |
794 |
795 |
796 |
797 |
798 |
799 |
800 |
801 |
802 |
803 |
804 |
805 |
806 |
807 |
808 |
809 |
810 |
811 |
812 |
813 |
814 |
815 |
816 |
817 |
818 |
819 |
820 |
821 |
822 |
823 |
824 |
825 |
826 |
827 |
828 |
829 |
830 |
831 |
832 |
833 |
834 |
835 |
836 |
837 |
838 |
839 |
840 |
841 |
842 |
843 |
844 |
845 |
846 |
847 |
848 |
849 |
850 |
851 |
852 |
853 |
854 |
855 |
856 |
857 |
858 |
859 |
860 |
861 |
862 |
863 |
864 |
865 |
866 |
867 |
868 |
869 |
870 |
871 |
872 |
873 |
874 |
875 |
876 |
877 |
878 |
879 |
880 |
881 |
882 |
883 |
884 |
885 |
886 |
887 |
888 |
889 |
890 |
891 |
892 |
893 |
894 |
895 |
896 |
897 |
898 |
899 |
900 |
901 |
902 |
903 |
904 |
905 |
906 |
907 |
908 |
909 |
910 |
911 |
912 |
913 |
914 |
915 |
916 |
917 |
918 |
919 |
920 |
921 |
922 |
923 |
924 |
925 |
926 |
927 |
928 |
929 |
930 |
931 |
932 |
933 |
934 |
935 |
936 |
937 |
938 |
939 |
940 |
941 |
942 |
943 |
944 |
945 |
946 |
947 |
948 |
949 |
950 |
951 |
952 |
953 |
954 |
955 |
956 |
957 |
958 |
959 |
960 |
961 |
962 |
963 |
964 |
965 |
966 |
967 |
968 |
969 |
970 |
971 |
972 |
973 |
974 |
975 |
976 |
977 |
978 |
979 |
980 |
981 |
982 |
983 |
984 |
985 |
986 |
987 |
988 |
989 |
990 |
991 |
992 |
993 |
994 |
995 |
996 |
997 |
998 |
999 |
1000 |
1001 |
1002 |
1003 |
1004 |
1005 |
1006 |
1007 |
1008 |
1009 |
1010 |
1011 |
1012 |
1013 |
1014 |
1015 |
1016 |
1017 |
1018 |
1019 |
1020 |
1021 |
1022 |
1023 |
1024 |
1025 |
1026 |
1027 |
1028 |
1029 |
1030 |
1031 |
1032 |
1033 |
1034 |
1035 |
1036 |
1037 |
1038 |
1039 |
1040 |
1041 |
1042 |
1043 |
1044 |
1045 |
1046 |
1047 |
1048 |
1049 |
1050 |
1051 |
1052 |
1053 |
1054 |
1055 |
1056 |
1057 |
1058 |
1059 |
1060 |
1061 |
1062 |
1063 |
1064 |
1065 |
1066 |
1067 |
1068 |
1069 |
1070 |
1071 |
1072 |
1073 |
1074 |
1075 |
1076 |
1077 |
1078 |
1079 |
1080 |
1081 |
1082 |
1083 |
1084 |
1085 |
1086 |
1087 |
1088 |
1089 |
1090 |
1091 |
1092 |
1093 |
1094 |
1095 |
1096 |
1097 |
1098 |
1099 |
1100 |
1101 |
1102 |
1103 |
1104 |
1105 |
1106 |
1107 |
1108 |
1109 |
1110 |
1111 |
1112 |
1113 |
1114 |
1115 |
1116 |
1117 |
1118 |
1119 |
1120 |
1121 |
1122 |
1123 |
1124 |
1125 |
1126 |
1127 |
1128 |
1129 |
1130 |
1131 |
1132 |
--------------------------------------------------------------------------------