motion-kramdown 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +84 -0
- data/lib/kramdown/compatibility.rb +36 -0
- data/lib/kramdown/converter/base.rb +259 -0
- data/lib/kramdown/converter/html.rb +461 -0
- data/lib/kramdown/converter/kramdown.rb +423 -0
- data/lib/kramdown/converter/latex.rb +600 -0
- data/lib/kramdown/converter/math_engine/itex2mml.rb +39 -0
- data/lib/kramdown/converter/math_engine/mathjax.rb +33 -0
- data/lib/kramdown/converter/math_engine/ritex.rb +38 -0
- data/lib/kramdown/converter/pdf.rb +624 -0
- data/lib/kramdown/converter/remove_html_tags.rb +53 -0
- data/lib/kramdown/converter/syntax_highlighter/coderay.rb +78 -0
- data/lib/kramdown/converter/syntax_highlighter/rouge.rb +37 -0
- data/lib/kramdown/converter/toc.rb +69 -0
- data/lib/kramdown/converter.rb +69 -0
- data/lib/kramdown/document.rb +144 -0
- data/lib/kramdown/element.rb +515 -0
- data/lib/kramdown/error.rb +17 -0
- data/lib/kramdown/options.rb +584 -0
- data/lib/kramdown/parser/base.rb +130 -0
- data/lib/kramdown/parser/gfm.rb +55 -0
- data/lib/kramdown/parser/html.rb +575 -0
- data/lib/kramdown/parser/kramdown/abbreviation.rb +67 -0
- data/lib/kramdown/parser/kramdown/autolink.rb +37 -0
- data/lib/kramdown/parser/kramdown/blank_line.rb +30 -0
- data/lib/kramdown/parser/kramdown/block_boundary.rb +33 -0
- data/lib/kramdown/parser/kramdown/blockquote.rb +39 -0
- data/lib/kramdown/parser/kramdown/codeblock.rb +56 -0
- data/lib/kramdown/parser/kramdown/codespan.rb +44 -0
- data/lib/kramdown/parser/kramdown/emphasis.rb +61 -0
- data/lib/kramdown/parser/kramdown/eob.rb +26 -0
- data/lib/kramdown/parser/kramdown/escaped_chars.rb +25 -0
- data/lib/kramdown/parser/kramdown/extensions.rb +201 -0
- data/lib/kramdown/parser/kramdown/footnote.rb +56 -0
- data/lib/kramdown/parser/kramdown/header.rb +59 -0
- data/lib/kramdown/parser/kramdown/horizontal_rule.rb +27 -0
- data/lib/kramdown/parser/kramdown/html.rb +160 -0
- data/lib/kramdown/parser/kramdown/html_entity.rb +33 -0
- data/lib/kramdown/parser/kramdown/line_break.rb +25 -0
- data/lib/kramdown/parser/kramdown/link.rb +139 -0
- data/lib/kramdown/parser/kramdown/list.rb +256 -0
- data/lib/kramdown/parser/kramdown/math.rb +54 -0
- data/lib/kramdown/parser/kramdown/paragraph.rb +54 -0
- data/lib/kramdown/parser/kramdown/smart_quotes.rb +174 -0
- data/lib/kramdown/parser/kramdown/table.rb +171 -0
- data/lib/kramdown/parser/kramdown/typographic_symbol.rb +44 -0
- data/lib/kramdown/parser/kramdown.rb +359 -0
- data/lib/kramdown/parser/markdown.rb +56 -0
- data/lib/kramdown/parser.rb +27 -0
- data/lib/kramdown/utils/configurable.rb +44 -0
- data/lib/kramdown/utils/entities.rb +347 -0
- data/lib/kramdown/utils/html.rb +75 -0
- data/lib/kramdown/utils/ordered_hash.rb +87 -0
- data/lib/kramdown/utils/string_scanner.rb +74 -0
- data/lib/kramdown/utils/unidecoder.rb +51 -0
- data/lib/kramdown/utils.rb +58 -0
- data/lib/kramdown/version.rb +15 -0
- data/lib/kramdown.rb +10 -0
- data/lib/motion-kramdown.rb +47 -0
- data/lib/rubymotion/encodings.rb +37 -0
- data/lib/rubymotion/rexml_shim.rb +25 -0
- data/lib/rubymotion/set.rb +1349 -0
- data/lib/rubymotion/version.rb +6 -0
- data/spec/document_tree.rb +48 -0
- data/spec/gfm_to_html.rb +95 -0
- data/spec/helpers/it_behaves_like.rb +27 -0
- data/spec/helpers/option_file.rb +46 -0
- data/spec/helpers/spec_options.rb +37 -0
- data/spec/helpers/tidy.rb +12 -0
- data/spec/html_to_html.rb +40 -0
- data/spec/html_to_kramdown_to_html.rb +46 -0
- data/spec/kramdown_to_xxx.rb +40 -0
- data/spec/test_location.rb +203 -0
- data/spec/test_string_scanner_kramdown.rb +19 -0
- data/spec/text_to_kramdown_to_html.rb +52 -0
- data/spec/text_to_latex.rb +33 -0
- metadata +164 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8fd59aa42442a883766e182755509ca88a104fd6
|
4
|
+
data.tar.gz: 1b6950617b913dd6b6008e5e3790476dffc4e00d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3fe906689c82391b256133cdd1ce0283f6ab10aea5c1ed1761c2071210f5060c7cd4836fa81555a88d82196f3839020f967e6cb6be6d833e06051881cb19f611
|
7
|
+
data.tar.gz: d9432cefa45a87160dad48bb861ce7d281597f7b44b5cf32186f640a17edac6f40ed993f3ff879019f1a35b1bda2d1e8ac31122066cbcab2d85150ee00fb3ee3
|
data/README.md
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
# motion-kramdown
|
2
|
+
|
3
|
+
This is a light modification of the [kramdown](https://github.com/gettalong/kramdown) Markdown parser, for use with RubyMotion on iOS and OS X.
|
4
|
+
|
5
|
+
Currently implements: _kramdown_ 1.5
|
6
|
+
|
7
|
+
## Introduction
|
8
|
+
|
9
|
+
_kramdown_ is yet-another-markdown-parser but fast, pure Ruby, using a strict syntax definition and supporting several common extensions.
|
10
|
+
|
11
|
+
The syntax definition for the kramdown syntax can be found in **doc/syntax.page** (or online at <http://kramdown.gettalong.org/syntax.html>) and a quick reference is available in **doc/quickref.page** or online at <http://kramdown.gettalong.org/quickref.html>.
|
12
|
+
|
13
|
+
The _kramdown_ library is mainly written to support the kramdown-to-HTML conversion chain. However, due to its flexibility it supports other input and output formats as well. Here is a list of the supported formats:
|
14
|
+
|
15
|
+
* input formats: kramdown (a Markdown superset), Markdown, HTML
|
16
|
+
* output formats: HTML, kramdown (and LaTeX and PDF, though not in _motion-kramdown_)
|
17
|
+
|
18
|
+
All the documentation on the available input and output formats is available in the **doc/** directory and online at <http://kramdown.gettalong.org>.
|
19
|
+
|
20
|
+
## Installation
|
21
|
+
|
22
|
+
Add it to your project's `Gemfile`
|
23
|
+
|
24
|
+
gem 'motion-kramdown'
|
25
|
+
|
26
|
+
Edit your `Rakefile` and add
|
27
|
+
|
28
|
+
require 'motion-kramdown'
|
29
|
+
|
30
|
+
## Usage
|
31
|
+
|
32
|
+
_motion-kramdown_ uses the same api and options as _kramdown_
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
Kramdown::Document.new(text).to_html
|
36
|
+
```
|
37
|
+
|
38
|
+
For detailed information on usage and options, see the [kramdown documentation](http://kramdown.gettalong.org/documentation.html). The full kramdown RDoc documentation is available at <http://kramdown.gettalong.org/rdoc/>
|
39
|
+
|
40
|
+
## Supported Features
|
41
|
+
|
42
|
+
The entire kramdown api is supported, except where noted below.
|
43
|
+
|
44
|
+
### Missing Features
|
45
|
+
|
46
|
+
These items are currently not supported
|
47
|
+
|
48
|
+
1. transliterated header ids
|
49
|
+
2. math engines: MathJax, Ritex, and itex2MML
|
50
|
+
3. syntax highlighters: Coderay and Rouge
|
51
|
+
4. Latex
|
52
|
+
5. PDF
|
53
|
+
6. using template files or the :template option
|
54
|
+
7. Andriod support (will accept pull requests)
|
55
|
+
|
56
|
+
## Testing
|
57
|
+
|
58
|
+
Test files are located in the `spec` directory. The `test` directory contains the original kramdown test and data files, which are used in the specs.
|
59
|
+
|
60
|
+
#--- run the entire test suite
|
61
|
+
rake spec
|
62
|
+
|
63
|
+
#--- run just the kramdown converter tests
|
64
|
+
rake spec files=kramdown_to_xxx
|
65
|
+
|
66
|
+
#--- run test for specific data files
|
67
|
+
rake spec files=kramdown_to_xxx focus=block/03_paragraph
|
68
|
+
|
69
|
+
## Issues
|
70
|
+
|
71
|
+
If you run into any problems with the gem,
|
72
|
+
|
73
|
+
1. First see if the problem exists with the regular _kramdown_ gem. If it does, then the issue should be opened on the [main kramdown repository](https://github.com/gettalong/kramdown)
|
74
|
+
2. Open an issue on this repository
|
75
|
+
|
76
|
+
## Credit
|
77
|
+
|
78
|
+
All credit for _kramdown_ belongs to Thomas Leitner. _motion-kramdown_ is a simple modifcation to make it work with RubyMotion.
|
79
|
+
|
80
|
+
## License
|
81
|
+
|
82
|
+
_motion-kramdown_ is released under the MIT license (see the **COPYING** file) and therefore can easily be used in commercial projects.
|
83
|
+
|
84
|
+
However, if you use _motion-kramdown_ in a commercial setting, please consider **contributing back any changes** for the benefit of the community and/or **making a donation** (see the links in the sidebar on the [kramdown homepage](http://kramdown.gettalong.org/).
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2014 Thomas Leitner <t_leitner@gmx.at>
|
5
|
+
#
|
6
|
+
# This file is part of kramdown which is licensed under the MIT.
|
7
|
+
#++
|
8
|
+
#
|
9
|
+
# All the code in this file is backported from Ruby 1.8.7 sothat kramdown works under 1.8.5
|
10
|
+
#
|
11
|
+
# :stopdoc:
|
12
|
+
|
13
|
+
if RUBY_VERSION <= '1.8.6'
|
14
|
+
# RM require 'rexml/parsers/baseparser'
|
15
|
+
module REXML
|
16
|
+
module Parsers
|
17
|
+
class BaseParser
|
18
|
+
UNAME_STR= "(?:#{NCNAME_STR}:)?#{NCNAME_STR}" unless const_defined?(:UNAME_STR)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
if !String.instance_methods.include?("start_with?")
|
24
|
+
|
25
|
+
class String
|
26
|
+
def start_with?(str)
|
27
|
+
self[0, str.length] == str
|
28
|
+
end
|
29
|
+
def end_with?(str)
|
30
|
+
self[-str.length, str.length] == str
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,259 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (C) 2009-2014 Thomas Leitner <t_leitner@gmx.at>
|
5
|
+
#
|
6
|
+
# This file is part of kramdown which is licensed under the MIT.
|
7
|
+
#++
|
8
|
+
#
|
9
|
+
|
10
|
+
# RM require 'erb'
|
11
|
+
# RM require 'kramdown/utils'
|
12
|
+
|
13
|
+
module Kramdown
|
14
|
+
|
15
|
+
module Converter
|
16
|
+
|
17
|
+
# == \Base class for converters
|
18
|
+
#
|
19
|
+
# This class serves as base class for all converters. It provides methods that can/should be
|
20
|
+
# used by all converters (like #generate_id) as well as common functionality that is
|
21
|
+
# automatically applied to the result (for example, embedding the output into a template).
|
22
|
+
#
|
23
|
+
# A converter object is used as a throw-away object, i.e. it is only used for storing the needed
|
24
|
+
# state information during conversion. Therefore one can't instantiate a converter object
|
25
|
+
# directly but only use the Base::convert method.
|
26
|
+
#
|
27
|
+
# == Implementing a converter
|
28
|
+
#
|
29
|
+
# Implementing a new converter is rather easy: just derive a new class from this class and put
|
30
|
+
# it in the Kramdown::Converter module (the latter is only needed if auto-detection should work
|
31
|
+
# properly). Then you need to implement the #convert method which has to contain the conversion
|
32
|
+
# code for converting an element and has to return the conversion result.
|
33
|
+
#
|
34
|
+
# The actual transformation of the document tree can be done in any way. However, writing one
|
35
|
+
# method per element type is a straight forward way to do it - this is how the Html and Latex
|
36
|
+
# converters do the transformation.
|
37
|
+
#
|
38
|
+
# Have a look at the Base::convert method for additional information!
|
39
|
+
class Base
|
40
|
+
|
41
|
+
# Can be used by a converter for storing arbitrary information during the conversion process.
|
42
|
+
attr_reader :data
|
43
|
+
|
44
|
+
# The hash with the conversion options.
|
45
|
+
attr_reader :options
|
46
|
+
|
47
|
+
# The root element that is converted.
|
48
|
+
attr_reader :root
|
49
|
+
|
50
|
+
# The warnings array.
|
51
|
+
attr_reader :warnings
|
52
|
+
|
53
|
+
# Initialize the converter with the given +root+ element and +options+ hash.
|
54
|
+
def initialize(root, options)
|
55
|
+
@options = options
|
56
|
+
@root = root
|
57
|
+
@data = {}
|
58
|
+
@warnings = []
|
59
|
+
end
|
60
|
+
private_class_method(:new, :allocate)
|
61
|
+
|
62
|
+
# Returns whether the template should be applied before the conversion of the tree.
|
63
|
+
#
|
64
|
+
# Defaults to false.
|
65
|
+
def apply_template_before?
|
66
|
+
false
|
67
|
+
end
|
68
|
+
|
69
|
+
# Returns whether the template should be applied ater the conversion of the tree.
|
70
|
+
#
|
71
|
+
# Defaults to true.
|
72
|
+
def apply_template_after?
|
73
|
+
true
|
74
|
+
end
|
75
|
+
|
76
|
+
# Convert the element tree +tree+ and return the resulting conversion object (normally a
|
77
|
+
# string) and an array with warning messages. The parameter +options+ specifies the conversion
|
78
|
+
# options that should be used.
|
79
|
+
#
|
80
|
+
# Initializes a new instance of the calling class and then calls the #convert method with
|
81
|
+
# +tree+ as parameter.
|
82
|
+
#
|
83
|
+
# If the +template+ option is specified and non-empty, the template is evaluate with ERB
|
84
|
+
# before and/or after the tree conversion depending on the result of #apply_template_before?
|
85
|
+
# and #apply_template_after?. If the template is evaluated before, an empty string is used for
|
86
|
+
# the body; if evaluated after, the result is used as body. See ::apply_template.
|
87
|
+
#
|
88
|
+
# The template resolution is done in the following way (for the converter ConverterName):
|
89
|
+
#
|
90
|
+
# 1. Look in the current working directory for the template.
|
91
|
+
#
|
92
|
+
# 2. Append +.converter_name+ (e.g. +.html+) to the template name and look for the resulting
|
93
|
+
# file in the current working directory (the form +.convertername+ is deprecated).
|
94
|
+
#
|
95
|
+
# 3. Append +.converter_name+ to the template name and look for it in the kramdown data
|
96
|
+
# directory (the form +.convertername+ is deprecated).
|
97
|
+
#
|
98
|
+
# 4. Check if the template name starts with 'string://' and if so, strip this prefix away and
|
99
|
+
# use the rest as template.
|
100
|
+
def self.convert(tree, options = {})
|
101
|
+
converter = new(tree, ::Kramdown::Options.merge(options.merge(tree.options[:options] || {})))
|
102
|
+
|
103
|
+
apply_template(converter, '') if !converter.options[:template].empty? && converter.apply_template_before?
|
104
|
+
result = converter.convert(tree)
|
105
|
+
result.encode!(tree.options[:encoding]) if result.respond_to?(:encode!) && result.encoding != Encoding::BINARY
|
106
|
+
result = apply_template(converter, result) if !converter.options[:template].empty? && converter.apply_template_after?
|
107
|
+
|
108
|
+
[result, converter.warnings]
|
109
|
+
end
|
110
|
+
|
111
|
+
# Convert the element +el+ and return the resulting object.
|
112
|
+
#
|
113
|
+
# This is the only method that has to be implemented by sub-classes!
|
114
|
+
def convert(el)
|
115
|
+
raise NotImplementedError
|
116
|
+
end
|
117
|
+
|
118
|
+
# Apply the +template+ using +body+ as the body string.
|
119
|
+
#
|
120
|
+
# The template is evaluated using ERB and the body is available in the @body instance variable
|
121
|
+
# and the converter object in the @converter instance variable.
|
122
|
+
def self.apply_template(converter, body) # :nodoc:
|
123
|
+
erb = ERB.new(get_template(converter.options[:template]))
|
124
|
+
obj = Object.new
|
125
|
+
obj.instance_variable_set(:@converter, converter)
|
126
|
+
obj.instance_variable_set(:@body, body)
|
127
|
+
erb.result(obj.instance_eval{binding})
|
128
|
+
end
|
129
|
+
|
130
|
+
# Return the template specified by +template+.
|
131
|
+
def self.get_template(template)
|
132
|
+
#DEPRECATED: use content of #get_template_new in 2.0
|
133
|
+
format_ext = '.' + self.name.split(/::/).last.downcase
|
134
|
+
shipped = File.join(::Kramdown.data_dir, template + format_ext)
|
135
|
+
if File.exist?(template)
|
136
|
+
File.read(template)
|
137
|
+
elsif File.exist?(template + format_ext)
|
138
|
+
File.read(template + format_ext)
|
139
|
+
elsif File.exist?(shipped)
|
140
|
+
File.read(shipped)
|
141
|
+
elsif template.start_with?('string://')
|
142
|
+
template.sub(/\Astring:\/\//, '')
|
143
|
+
else
|
144
|
+
get_template_new(template)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def self.get_template_new(template) # :nodoc:
|
149
|
+
format_ext = '.' + ::Kramdown::Utils.snake_case(self.name.split(/::/).last)
|
150
|
+
shipped = File.join(::Kramdown.data_dir, template + format_ext)
|
151
|
+
if File.exist?(template)
|
152
|
+
File.read(template)
|
153
|
+
elsif File.exist?(template + format_ext)
|
154
|
+
File.read(template + format_ext)
|
155
|
+
elsif File.exist?(shipped)
|
156
|
+
File.read(shipped)
|
157
|
+
elsif template.start_with?('string://')
|
158
|
+
template.sub(/\Astring:\/\//, '')
|
159
|
+
else
|
160
|
+
raise "The specified template file #{template} does not exist"
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# Add the given warning +text+ to the warning array.
|
165
|
+
def warning(text)
|
166
|
+
@warnings << text
|
167
|
+
end
|
168
|
+
|
169
|
+
# Return +true+ if the header element +el+ should be used for the table of contents (as
|
170
|
+
# specified by the +toc_levels+ option).
|
171
|
+
def in_toc?(el)
|
172
|
+
@options[:toc_levels].include?(el.options[:level]) && (el.attr['class'] || '') !~ /\bno_toc\b/
|
173
|
+
end
|
174
|
+
|
175
|
+
# Return the output header level given a level.
|
176
|
+
#
|
177
|
+
# Uses the +header_offset+ option for adjusting the header level.
|
178
|
+
def output_header_level(level)
|
179
|
+
[[level + @options[:header_offset], 6].min, 1].max
|
180
|
+
end
|
181
|
+
|
182
|
+
# Extract the code block/span language from the attributes.
|
183
|
+
def extract_code_language(attr)
|
184
|
+
if attr['class'] && attr['class'] =~ /\blanguage-\w+\b/
|
185
|
+
attr['class'].scan(/\blanguage-(\w+)\b/).first.first
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# See #extract_code_language
|
190
|
+
#
|
191
|
+
# *Warning*: This version will modify the given attributes if a language is present.
|
192
|
+
def extract_code_language!(attr)
|
193
|
+
lang = extract_code_language(attr)
|
194
|
+
attr['class'] = attr['class'].sub(/\blanguage-\w+\b/, '').strip if lang
|
195
|
+
attr.delete('class') if lang && attr['class'].empty?
|
196
|
+
lang
|
197
|
+
end
|
198
|
+
|
199
|
+
# Highlight the given +text+ in the language +lang+ with the syntax highlighter configured
|
200
|
+
# through the option 'syntax_highlighter'.
|
201
|
+
def highlight_code(text, lang, type, opts = {})
|
202
|
+
return nil unless @options[:syntax_highlighter]
|
203
|
+
|
204
|
+
highlighter = ::Kramdown::Converter.syntax_highlighter(@options[:syntax_highlighter])
|
205
|
+
if highlighter
|
206
|
+
highlighter.call(self, text, lang, type, opts)
|
207
|
+
else
|
208
|
+
warning("The configured syntax highlighter #{@options[:syntax_highlighter]} is not available.")
|
209
|
+
nil
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
# Format the given math element with the math engine configured through the option
|
214
|
+
# 'math_engine'.
|
215
|
+
def format_math(el, opts = {})
|
216
|
+
return nil unless @options[:math_engine]
|
217
|
+
|
218
|
+
engine = ::Kramdown::Converter.math_engine(@options[:math_engine])
|
219
|
+
if engine
|
220
|
+
engine.call(self, el, opts)
|
221
|
+
else
|
222
|
+
warning("The configured math engine #{@options[:math_engine]} is not available.")
|
223
|
+
nil
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
# Generate an unique alpha-numeric ID from the the string +str+ for use as a header ID.
|
228
|
+
#
|
229
|
+
# Uses the option +auto_id_prefix+: the value of this option is prepended to every generated
|
230
|
+
# ID.
|
231
|
+
def generate_id(str)
|
232
|
+
str = ::Kramdown::Utils::Unidecoder.decode(str) if @options[:transliterated_header_ids]
|
233
|
+
gen_id = str.gsub(/^[^a-zA-Z]+/, '')
|
234
|
+
gen_id.tr!('^a-zA-Z0-9 -', '')
|
235
|
+
gen_id.tr!(' ', '-')
|
236
|
+
gen_id.downcase!
|
237
|
+
gen_id = 'section' if gen_id.length == 0
|
238
|
+
@used_ids ||= {}
|
239
|
+
if @used_ids.has_key?(gen_id)
|
240
|
+
gen_id += '-' << (@used_ids[gen_id] += 1).to_s
|
241
|
+
else
|
242
|
+
@used_ids[gen_id] = 0
|
243
|
+
end
|
244
|
+
@options[:auto_id_prefix] + gen_id
|
245
|
+
end
|
246
|
+
|
247
|
+
SMART_QUOTE_INDICES = {:lsquo => 0, :rsquo => 1, :ldquo => 2, :rdquo => 3} # :nodoc:
|
248
|
+
|
249
|
+
# Return the entity that represents the given smart_quote element.
|
250
|
+
def smart_quote_entity(el)
|
251
|
+
res = @options[:smart_quotes][SMART_QUOTE_INDICES[el.value]]
|
252
|
+
::Kramdown::Utils::Entities.entity(res)
|
253
|
+
end
|
254
|
+
|
255
|
+
end
|
256
|
+
|
257
|
+
end
|
258
|
+
|
259
|
+
end
|