rmultimarkdown 4.6.0.2 → 4.7.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.
- checksums.yaml +4 -4
- data/MultiMarkdown-4/GLibFacade.c +16 -0
- data/MultiMarkdown-4/GLibFacade.h +1 -0
- data/MultiMarkdown-4/beamer.c +3 -2
- data/MultiMarkdown-4/critic.c +1 -1
- data/MultiMarkdown-4/html.c +6 -1
- data/MultiMarkdown-4/latex.c +4 -1
- data/MultiMarkdown-4/libMultiMarkdown.h +3 -1
- data/MultiMarkdown-4/lyx.c +3 -0
- data/MultiMarkdown-4/memoir.c +1 -1
- data/MultiMarkdown-4/multimarkdown.c +59 -13
- data/MultiMarkdown-4/odf.c +4 -1
- data/MultiMarkdown-4/opml.c +1 -1
- data/MultiMarkdown-4/parse_utilities.c +10 -2
- data/MultiMarkdown-4/parser.c +7070 -6682
- data/MultiMarkdown-4/parser.h +4 -2
- data/MultiMarkdown-4/rtf.c +14 -0
- data/MultiMarkdown-4/text.c +1 -1
- data/MultiMarkdown-4/toc.c +142 -0
- data/MultiMarkdown-4/toc.h +15 -0
- data/MultiMarkdown-4/transclude.c +78 -5
- data/MultiMarkdown-4/transclude.h +3 -2
- data/MultiMarkdown-4/writer.c +19 -5
- data/MultiMarkdown-4/writer.h +1 -0
- data/lib/multi_markdown.bundle +0 -0
- data/lib/multi_markdown/version.rb +1 -1
- metadata +36 -34
data/MultiMarkdown-4/parser.h
CHANGED
@@ -14,10 +14,10 @@
|
|
14
14
|
|
15
15
|
#define TABSTOP 4
|
16
16
|
|
17
|
-
#define MMD_VERSION "4.
|
17
|
+
#define MMD_VERSION "4.7"
|
18
18
|
|
19
19
|
#define MMD_COPYRIGHT \
|
20
|
-
"Copyright (c) 2013-
|
20
|
+
"Copyright (c) 2013-2015 Fletcher T. Penney.\n\n" \
|
21
21
|
"LyX export code (c) 2013-2014 Charles R. Cowan,\n" \
|
22
22
|
"licensed under both GPL and MIT licenses.\n\n" \
|
23
23
|
"portions based on peg-markdown - Copyright (c) 2008-2009 John MacFarlane.\n" \
|
@@ -71,6 +71,7 @@ typedef struct {
|
|
71
71
|
int odf_para_type; /* what type of paragraph do we need? */
|
72
72
|
bool odf_list_needs_end_p; /* is there a <p> that need to be closed */
|
73
73
|
int random_seed_base; /* Allow random footnotes */
|
74
|
+
int toc_level; /* Track depth for TOC */
|
74
75
|
int table_row; /* CRC - Track the current row number */
|
75
76
|
int lyx_para_type; /* CRC - the type of paragraph being processed */
|
76
77
|
int lyx_level; /* CRC - nesting level */
|
@@ -180,5 +181,6 @@ int tree_contains_key_count(node *list, int key);
|
|
180
181
|
bool check_timeout();
|
181
182
|
|
182
183
|
void debug_node(node *n);
|
184
|
+
void debug_node_tree(node *n);
|
183
185
|
|
184
186
|
#endif
|
data/MultiMarkdown-4/rtf.c
CHANGED
@@ -474,6 +474,20 @@ void print_rtf_node(GString *out, node *n, scratch_pad *scratch) {
|
|
474
474
|
free(temp);
|
475
475
|
}
|
476
476
|
break;
|
477
|
+
case HTMLBLOCK:
|
478
|
+
/* don't print HTML block */
|
479
|
+
/* but do print HTML comments for raw RTF */
|
480
|
+
if (strncmp(n->str,"<!--",4) == 0) {
|
481
|
+
pad(out, 2, scratch);
|
482
|
+
/* trim "-->" from end */
|
483
|
+
n->str[strlen(n->str)-3] = '\0';
|
484
|
+
g_string_append_printf(out, "%s", &n->str[4]);
|
485
|
+
scratch->padded = 0;
|
486
|
+
}
|
487
|
+
break;
|
488
|
+
case TOC:
|
489
|
+
print_rtf_node_tree(out,n->children, scratch);
|
490
|
+
break;
|
477
491
|
default:
|
478
492
|
fprintf(stderr, "print_rtf_node encountered unknown node key = %d\n",n->key);
|
479
493
|
g_string_append_printf(out, "%s",n->str);
|
data/MultiMarkdown-4/text.c
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
test.c -- plain text writer function as an example.
|
4
4
|
Recreates the input source.
|
5
5
|
|
6
|
-
(c) 2013 Fletcher T. Penney (http://fletcherpenney.net/).
|
6
|
+
(c) 2013-2015 Fletcher T. Penney (http://fletcherpenney.net/).
|
7
7
|
|
8
8
|
This program is free software; you can redistribute it and/or modify
|
9
9
|
it under the terms of the GNU General Public License or the MIT
|
@@ -0,0 +1,142 @@
|
|
1
|
+
/*
|
2
|
+
|
3
|
+
toc.c -- Table of contents
|
4
|
+
|
5
|
+
(c) 2013-2015 Fletcher T. Penney (http://fletcherpenney.net/).
|
6
|
+
|
7
|
+
This program is free software; you can redistribute it and/or modify
|
8
|
+
it under the terms of the GNU General Public License or the MIT
|
9
|
+
license. See LICENSE for details.
|
10
|
+
|
11
|
+
This program is distributed in the hope that it will be useful,
|
12
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
GNU General Public License for more details.
|
15
|
+
|
16
|
+
*/
|
17
|
+
|
18
|
+
#include "toc.h"
|
19
|
+
|
20
|
+
|
21
|
+
/* print_toc_node_tree -- convert node tree to LaTeX */
|
22
|
+
void print_toc_node_tree(GString *out, node *list, scratch_pad *scratch) {
|
23
|
+
#ifdef DEBUG_ON
|
24
|
+
fprintf(stderr, "print_toc_node_tree\n");
|
25
|
+
#endif
|
26
|
+
int lev;
|
27
|
+
while (list != NULL) {
|
28
|
+
if (list->key == HEADINGSECTION) {
|
29
|
+
lev = list->children->key;
|
30
|
+
|
31
|
+
print_toc_section_and_children(out, list, scratch);
|
32
|
+
|
33
|
+
while ((list->next != NULL) && (list->next->key == HEADINGSECTION)
|
34
|
+
&& (list->next->children->key > lev)) {
|
35
|
+
list = list->next;
|
36
|
+
}
|
37
|
+
} else {
|
38
|
+
print_toc_node(out, list, scratch);
|
39
|
+
}
|
40
|
+
list = list->next;
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
/* print_toc_section_and_children -- we want to stay inside the outline structure */
|
45
|
+
void print_toc_section_and_children(GString *out, node *list, scratch_pad *scratch) {
|
46
|
+
#ifdef DEBUG_ON
|
47
|
+
fprintf(stderr, "print_toc_section_and_children: %d\n",list->key);
|
48
|
+
#endif
|
49
|
+
int lev = list->children->key;
|
50
|
+
|
51
|
+
/* print current section (parent) */
|
52
|
+
print_toc_node(out, list, scratch);
|
53
|
+
|
54
|
+
scratch->toc_level ++;
|
55
|
+
|
56
|
+
/* check for child nodes */
|
57
|
+
while ((list->next != NULL) && (list->next->key == HEADINGSECTION) && (list->next->children->key > lev)) {
|
58
|
+
/* next item is also a HEADINGSECTION and is a child */
|
59
|
+
if (list->next->children->key - lev == 1)
|
60
|
+
print_toc_section_and_children(out, list->next, scratch);
|
61
|
+
list = list->next;
|
62
|
+
}
|
63
|
+
|
64
|
+
scratch->toc_level --;
|
65
|
+
}
|
66
|
+
|
67
|
+
/* print_toc_node -- convert given node to OPML and append */
|
68
|
+
void print_toc_node(GString *out, node *n, scratch_pad *scratch) {
|
69
|
+
char *temp;
|
70
|
+
int i;
|
71
|
+
|
72
|
+
#ifdef DEBUG_ON
|
73
|
+
fprintf(stderr, "print_toc_node: %d\n",n->key);
|
74
|
+
#endif
|
75
|
+
switch (n->key) {
|
76
|
+
case HEADINGSECTION:
|
77
|
+
/* Need to handle "nesting" properly */
|
78
|
+
for (i = 0; i < scratch->toc_level; ++i)
|
79
|
+
{
|
80
|
+
g_string_append_printf(out, "\t");
|
81
|
+
}
|
82
|
+
g_string_append_printf(out, "* ");
|
83
|
+
|
84
|
+
/* Print header */
|
85
|
+
print_toc_node(out, n->children, scratch);
|
86
|
+
|
87
|
+
break;
|
88
|
+
case H1: case H2: case H3: case H4: case H5: case H6:
|
89
|
+
if ((n->children != NULL) && (n->children->key == AUTOLABEL)) {
|
90
|
+
temp = label_from_string(n->children->str);
|
91
|
+
/* use label for header since one was specified (MMD)*/
|
92
|
+
g_string_append_printf(out, "[");
|
93
|
+
print_toc_node_tree(out, n->children, scratch);
|
94
|
+
g_string_append_printf(out, "][%s]\n", temp);
|
95
|
+
} else {
|
96
|
+
temp = label_from_node_tree(n->children);
|
97
|
+
g_string_append_printf(out, "[");
|
98
|
+
print_toc_node_tree(out, n->children, scratch);
|
99
|
+
g_string_append_printf(out, "][%s]\n", temp);
|
100
|
+
}
|
101
|
+
free(temp);
|
102
|
+
break;
|
103
|
+
case STR:
|
104
|
+
print_toc_string(out, n->str);
|
105
|
+
break;
|
106
|
+
case SPACE:
|
107
|
+
g_string_append_printf(out, "%s", n->str);
|
108
|
+
break;
|
109
|
+
case LINK:
|
110
|
+
print_toc_node_tree(out, n->children, scratch);
|
111
|
+
break;
|
112
|
+
case LINKREFERENCE:
|
113
|
+
break;
|
114
|
+
case AUTOLABEL:
|
115
|
+
break;
|
116
|
+
case LIST:
|
117
|
+
print_toc_node_tree(out, n->children, scratch);
|
118
|
+
break;
|
119
|
+
default: fprintf(stderr, "print_html_node encountered unknown node key = %d\n",n->key);
|
120
|
+
break;
|
121
|
+
}
|
122
|
+
#ifdef DEBUG_ON
|
123
|
+
fprintf(stderr, "finish print_toc_node: %d\n", n->key);
|
124
|
+
#endif
|
125
|
+
}
|
126
|
+
|
127
|
+
/* print_toc_string - print string, escaping for OPML */
|
128
|
+
void print_toc_string(GString *out, char *str) {
|
129
|
+
while (*str != '\0') {
|
130
|
+
switch (*str) {
|
131
|
+
case '[':
|
132
|
+
g_string_append_printf(out, "\\[");
|
133
|
+
break;
|
134
|
+
case ']':
|
135
|
+
g_string_append_printf(out, "\\]");
|
136
|
+
break;
|
137
|
+
default:
|
138
|
+
g_string_append_c(out, *str);
|
139
|
+
}
|
140
|
+
str++;
|
141
|
+
}
|
142
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
#ifndef TOC_PARSER_H
|
2
|
+
#define TOC_PARSER_H
|
3
|
+
|
4
|
+
#include "parser.h"
|
5
|
+
#include "writer.h"
|
6
|
+
|
7
|
+
void begin_toc_output(GString *out, node* list, scratch_pad *scratch);
|
8
|
+
void print_toc_node_tree(GString *out, node *list, scratch_pad *scratch);
|
9
|
+
void print_toc_node(GString *out, node *n, scratch_pad *scratch);
|
10
|
+
void print_toc_section_and_children(GString *out, node *list, scratch_pad *scratch);
|
11
|
+
void end_toc_output(GString *out, node* list, scratch_pad *scratch);
|
12
|
+
void print_toc_string(GString *out, char *str);
|
13
|
+
|
14
|
+
|
15
|
+
#endif
|
@@ -17,6 +17,9 @@
|
|
17
17
|
|
18
18
|
#include "transclude.h"
|
19
19
|
#include "parser.h"
|
20
|
+
#if defined(__WIN32)
|
21
|
+
#include <windows.h>
|
22
|
+
#endif
|
20
23
|
|
21
24
|
|
22
25
|
/* Combine directory and filename to create a full path */
|
@@ -48,19 +51,43 @@ char * path_from_dir_base(char *dir, char *base) {
|
|
48
51
|
return result;
|
49
52
|
}
|
50
53
|
|
54
|
+
/* Separate filename and directory from a full path */
|
55
|
+
/* See http://stackoverflow.com/questions/1575278/function-to-split-a-filepath-into-path-and-file */
|
56
|
+
void split_path_file(char** dir, char** file, char *path) {
|
57
|
+
char *slash = path, *next;
|
58
|
+
#if defined(__WIN32)
|
59
|
+
const char sep[] = "\\";
|
60
|
+
#else
|
61
|
+
const char sep[] = "/";
|
62
|
+
#endif
|
63
|
+
|
64
|
+
while ((next = strpbrk(slash + 1, sep))) slash = next;
|
65
|
+
if (path != slash) slash++;
|
66
|
+
*dir = strndup(path, slash - path);
|
67
|
+
*file = strdup(slash);
|
68
|
+
}
|
69
|
+
|
51
70
|
/* Return pointer to beginning of text without metadata */
|
71
|
+
/* NOTE: This is not a new string, and does not need to be freed separately */
|
52
72
|
char * source_without_metadata(char * source, unsigned long extensions ) {
|
53
73
|
char *result;
|
54
74
|
|
55
75
|
if (has_metadata(source, extensions)) {
|
56
76
|
/* If we have metadata, then return just the body */
|
77
|
+
/* TODO: This could miss YAML Metadata that does not contain
|
78
|
+
blank line afterwards */
|
57
79
|
result = strstr(source, "\n\n");
|
58
80
|
|
59
81
|
if (result != NULL)
|
60
|
-
return result+2;
|
82
|
+
return result + 2;
|
61
83
|
}
|
62
84
|
|
63
85
|
/* No metadata, so return original pointer */
|
86
|
+
|
87
|
+
/* But check for UTF-8 BOM and skip if present */
|
88
|
+
if (strncmp(source, "\xef\xbb\xbf",3) == 0)
|
89
|
+
return source + 3;
|
90
|
+
|
64
91
|
return source;
|
65
92
|
}
|
66
93
|
|
@@ -70,7 +97,7 @@ char * source_without_metadata(char * source, unsigned long extensions ) {
|
|
70
97
|
Pass the path to the current folder if available -- should be a full path.
|
71
98
|
|
72
99
|
Keep track of what we're parsing to prevent recursion using stack. */
|
73
|
-
void transclude_source(GString *source, char *basedir, char *stack, int output_format) {
|
100
|
+
void transclude_source(GString *source, char *basedir, char *stack, int output_format, GString *manifest) {
|
74
101
|
char *base = NULL;
|
75
102
|
char *path = NULL;
|
76
103
|
char *start;
|
@@ -165,6 +192,18 @@ void transclude_source(GString *source, char *basedir, char *stack, int output_f
|
|
165
192
|
|
166
193
|
pos = stop - source->str;
|
167
194
|
|
195
|
+
/* Add to the manifest (if not already included) */
|
196
|
+
if (manifest != NULL) {
|
197
|
+
temp = strstr(manifest->str,filename->str);
|
198
|
+
|
199
|
+
if ((temp != NULL) && (temp[strlen(filename->str)] == '\n')){
|
200
|
+
/* Already on manifest */
|
201
|
+
} else {
|
202
|
+
g_string_append_printf(manifest,"%s\n",filename->str);
|
203
|
+
}
|
204
|
+
}
|
205
|
+
|
206
|
+
|
168
207
|
/* Don't reparse ourselves */
|
169
208
|
if (stack != NULL) {
|
170
209
|
temp = strstr(stack,filename->str);
|
@@ -177,7 +216,15 @@ void transclude_source(GString *source, char *basedir, char *stack, int output_f
|
|
177
216
|
}
|
178
217
|
|
179
218
|
/* Read file */
|
219
|
+
#if defined(__WIN32)
|
220
|
+
int wchars_num = MultiByteToWideChar(CP_UTF8, 0, filename->str, -1, NULL, 0);
|
221
|
+
wchar_t wstr[wchars_num];
|
222
|
+
MultiByteToWideChar(CP_UTF8, 0, filename->str, -1, wstr, wchars_num);
|
223
|
+
|
224
|
+
if ((input = _wfopen(wstr, L"r")) != NULL ) {
|
225
|
+
#else
|
180
226
|
if ((input = fopen(filename->str, "r")) != NULL ) {
|
227
|
+
#endif
|
181
228
|
filebuffer = g_string_new("");
|
182
229
|
|
183
230
|
while ((curchar = fgetc(input)) != EOF)
|
@@ -195,8 +242,18 @@ void transclude_source(GString *source, char *basedir, char *stack, int output_f
|
|
195
242
|
|
196
243
|
|
197
244
|
/* Recursively transclude files */
|
198
|
-
transclude_source(filebuffer, folder->str, stackstring->str, output_format);
|
199
245
|
|
246
|
+
/* We want to reset the base directory if we enter a subdirectory */
|
247
|
+
char * new_dir;
|
248
|
+
char * file_only;
|
249
|
+
split_path_file(&new_dir, &file_only, filename->str);
|
250
|
+
|
251
|
+
/* transclude_source(filebuffer, folder->str, stackstring->str, output_format, manifest); */
|
252
|
+
transclude_source(filebuffer, new_dir, stackstring->str, output_format, manifest);
|
253
|
+
|
254
|
+
free(new_dir);
|
255
|
+
free(file_only);
|
256
|
+
|
200
257
|
temp = source_without_metadata(filebuffer->str, 0x000000);
|
201
258
|
|
202
259
|
g_string_insert(source, pos, temp);
|
@@ -224,11 +281,27 @@ void transclude_source(GString *source, char *basedir, char *stack, int output_f
|
|
224
281
|
/* Allow for a footer to specify files to be appended to the end of the text, and then transcluded.
|
225
282
|
Useful for appending a list of footnotes, citations, abbreviations, etc. to each separate file,
|
226
283
|
but not including multiple copies when processing the master file. */
|
227
|
-
void
|
284
|
+
void append_mmd_footer(GString *source) {
|
228
285
|
/* Look for mmd_footer metadata */
|
229
286
|
if (has_metadata(source->str, 0x000000)) {
|
230
287
|
char *meta = extract_metadata_value(source->str, 0x000000, "mmdfooter");
|
231
288
|
if (meta != NULL)
|
232
|
-
g_string_append_printf(source, "\n\n{{%s}}\n",meta);
|
289
|
+
g_string_append_printf(source, "\n\n{{%s}}\n", meta);
|
290
|
+
}
|
291
|
+
}
|
292
|
+
|
293
|
+
void prepend_mmd_header(GString *source) {
|
294
|
+
/* Same thing, but to be inserted after metadata and before content */
|
295
|
+
if (has_metadata(source->str, 0x000000)) {
|
296
|
+
char *meta = extract_metadata_value(source->str, 0x000000, "mmdheader");
|
297
|
+
if (meta != NULL) {
|
298
|
+
char *content = strstr(source->str, "\n\n");
|
299
|
+
if (content != NULL) {
|
300
|
+
size_t pos = content - source->str;
|
301
|
+
g_string_insert_printf(source, pos, "\n\n{{%s}}", meta);
|
302
|
+
} else {
|
303
|
+
g_string_append_printf(source, "\n\n{{%s}}\n", meta);
|
304
|
+
}
|
305
|
+
}
|
233
306
|
}
|
234
307
|
}
|
@@ -23,5 +23,6 @@
|
|
23
23
|
#include "GLibFacade.h"
|
24
24
|
|
25
25
|
char * source_without_metadata(char * source, unsigned long extensions);
|
26
|
-
void transclude_source(GString *source, char *basedir, char *stack, int format);
|
27
|
-
void
|
26
|
+
void transclude_source(GString *source, char *basedir, char *stack, int format, GString *manifest);
|
27
|
+
void append_mmd_footer(GString *source);
|
28
|
+
void prepend_mmd_header(GString *source);
|
data/MultiMarkdown-4/writer.c
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
writer.c -- General routines for converting parse structure to various
|
4
4
|
output formats.
|
5
5
|
|
6
|
-
(c) 2013 Fletcher T. Penney (http://fletcherpenney.net/).
|
6
|
+
(c) 2013-2015 Fletcher T. Penney (http://fletcherpenney.net/).
|
7
7
|
|
8
8
|
Derived from peg-multimarkdown, which was forked from peg-markdown,
|
9
9
|
which is (c) 2008 John MacFarlane (jgm at berkeley dot edu), and
|
@@ -41,13 +41,13 @@ char * export_node_tree(node *list, int format, unsigned long extensions) {
|
|
41
41
|
(format != CRITIC_ACCEPT_FORMAT) &&
|
42
42
|
(format != CRITIC_REJECT_FORMAT) &&
|
43
43
|
(format != CRITIC_HTML_HIGHLIGHT_FORMAT)) {
|
44
|
-
/* Parse for link, images, etc reference definitions */
|
45
|
-
extract_references(list, scratch);
|
46
|
-
|
47
44
|
/* Find defined abbreviations */
|
48
45
|
extract_abbreviations(list, scratch);
|
49
46
|
/* Apply those abbreviations to source text */
|
50
47
|
find_abbreviations(list, scratch);
|
48
|
+
|
49
|
+
/* Parse for link, images, etc reference definitions */
|
50
|
+
extract_references(list, scratch);
|
51
51
|
}
|
52
52
|
|
53
53
|
/* Change our desired format based on metadata */
|
@@ -138,6 +138,10 @@ char * export_node_tree(node *list, int format, unsigned long extensions) {
|
|
138
138
|
case CRITIC_HTML_HIGHLIGHT_FORMAT:
|
139
139
|
print_critic_html_highlight_node_tree(out, list, scratch);
|
140
140
|
break;
|
141
|
+
case TOC_FORMAT:
|
142
|
+
scratch->toc_level = 0;
|
143
|
+
print_toc_node_tree(out,list,scratch);
|
144
|
+
break;
|
141
145
|
default:
|
142
146
|
fprintf(stderr, "Unknown export format = %d\n",format);
|
143
147
|
exit(EXIT_FAILURE);
|
@@ -225,6 +229,8 @@ void extract_abbreviations(node *list, scratch_pad *scratch) {
|
|
225
229
|
case HEADINGSECTION:
|
226
230
|
case RAW:
|
227
231
|
case LIST:
|
232
|
+
case BLOCKQUOTEMARKER:
|
233
|
+
case BLOCKQUOTE:
|
228
234
|
extract_abbreviations(list->children, scratch);
|
229
235
|
break;
|
230
236
|
default:
|
@@ -293,11 +299,19 @@ void find_abbreviations(node *list, scratch_pad *scratch) {
|
|
293
299
|
}
|
294
300
|
break;
|
295
301
|
case LIST:
|
302
|
+
case ORDEREDLIST:
|
303
|
+
case BULLETLIST:
|
304
|
+
case LISTITEM:
|
296
305
|
case HEADINGSECTION:
|
297
306
|
case PARA:
|
307
|
+
case PLAIN:
|
298
308
|
case LINK:
|
299
309
|
case LINKREFERENCE:
|
300
310
|
case NOTEREFERENCE:
|
311
|
+
case NOTESOURCE:
|
312
|
+
case GLOSSARYSOURCE:
|
313
|
+
case BLOCKQUOTEMARKER:
|
314
|
+
case BLOCKQUOTE:
|
301
315
|
/* Check children of these elements */
|
302
316
|
find_abbreviations(list->children, scratch);
|
303
317
|
break;
|
@@ -714,4 +728,4 @@ link_data * load_link_data(node *n, scratch_pad *scratch) {
|
|
714
728
|
}
|
715
729
|
|
716
730
|
return r;
|
717
|
-
}
|
731
|
+
}
|