dragonfly_pdf 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +14 -23
- data/lib/dragonfly_pdf/analysers/pdf_properties.rb +7 -7
- data/lib/dragonfly_pdf/plugin.rb +4 -4
- data/lib/dragonfly_pdf/processors/page.rb +2 -2
- data/lib/dragonfly_pdf/processors/page_thumb.rb +3 -3
- data/lib/dragonfly_pdf/version.rb +1 -1
- data/test/dragonfly_pdf/analysers/pdf_properties_test.rb +31 -24
- data/test/dragonfly_pdf/plugin_test.rb +7 -2
- data/test/dragonfly_pdf/processors/page_test.rb +7 -0
- data/test/dragonfly_pdf/processors/page_thumb_test.rb +10 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2f7513fd9507eb6bf49ad4a51d4204264df9c758
|
4
|
+
data.tar.gz: 235b85f9685ea39fa14dd0e7d25edc876b66142d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6ceffc982e0b65454b263ce97e81aaac26104ac791026184020d2b4b8b9f012cf7dbad491bdc919ea85df685d64450a3193222b95896eea66e7f48214e485936
|
7
|
+
data.tar.gz: a18b986d6de46ba7ae00072da65b884dbf541dfdac594d2cfa453676236fecae4423304dccb208b4db28a987ce2ea4738bbbc72c92f37735a1b58d1224d2dd91
|
data/README.md
CHANGED
@@ -23,7 +23,7 @@ Or install it yourself as:
|
|
23
23
|
|
24
24
|
$ gem install dragonfly_pdf
|
25
25
|
|
26
|
-
##
|
26
|
+
## Usage
|
27
27
|
The analyser and processors are added by configuring the plugin
|
28
28
|
|
29
29
|
```ruby
|
@@ -32,25 +32,25 @@ Dragonfly.app.configure do
|
|
32
32
|
end
|
33
33
|
```
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
### PDF properties
|
35
|
+
### Spreads
|
38
36
|
|
39
|
-
|
37
|
+
PDFs that contain spreads (as when saving with the spreads option in InDesign) require setting the `spreads` [metadata](http://markevans.github.io/dragonfly/models/#meta-data) attribute to `true`:
|
40
38
|
|
41
39
|
```ruby
|
42
|
-
pdf.
|
40
|
+
pdf.metadata['spreads'] = true
|
43
41
|
```
|
44
42
|
|
45
|
-
|
43
|
+
## Analysers
|
44
|
+
|
45
|
+
### PDF properties
|
46
|
+
|
47
|
+
Reads properties from a PDF.
|
46
48
|
|
47
49
|
```ruby
|
48
|
-
|
49
|
-
spreads: false
|
50
|
-
}
|
50
|
+
pdf.pdf_properties
|
51
51
|
```
|
52
52
|
|
53
|
-
|
53
|
+
It returns a hash of properties:
|
54
54
|
|
55
55
|
```ruby
|
56
56
|
{
|
@@ -64,7 +64,7 @@ Returns Hash of PDF properties:
|
|
64
64
|
}
|
65
65
|
```
|
66
66
|
|
67
|
-
When the `spreads`
|
67
|
+
When the `spreads` metadata is set to `true`, the analyser assumes the PDF contains 2 real pages per one PDF page and recalculates the PDF properties accordingly (including situations where the PDF begins or ends with a single page). All page arrays (`page_numbers`, `widths`, `heights`, `aspect_ratios`) are then two dimensional (as illustrated above), representing spreads and nested individual pages.
|
68
68
|
|
69
69
|
## Processors
|
70
70
|
|
@@ -73,15 +73,7 @@ When the `spreads` argument is set to true, all page arrays (page_numbers, width
|
|
73
73
|
Extracts page from PDF.
|
74
74
|
|
75
75
|
```ruby
|
76
|
-
pdf.page(page_number=1
|
77
|
-
```
|
78
|
-
|
79
|
-
The available options and their default values are:
|
80
|
-
|
81
|
-
```ruby
|
82
|
-
{
|
83
|
-
spreads: false
|
84
|
-
}
|
76
|
+
pdf.page(page_number=1)
|
85
77
|
```
|
86
78
|
|
87
79
|
### Page Thumb
|
@@ -98,7 +90,6 @@ The available options and their default values are:
|
|
98
90
|
{
|
99
91
|
density: 600,
|
100
92
|
format: :png,
|
101
|
-
spreads: false
|
102
93
|
}
|
103
94
|
```
|
104
95
|
|
@@ -108,4 +99,4 @@ The available options and their default values are:
|
|
108
99
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
109
100
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
110
101
|
4. Push to the branch (`git push origin my-new-feature`)
|
111
|
-
5. Create a new Pull Request
|
102
|
+
5. Create a new Pull Request
|
@@ -4,19 +4,19 @@ module DragonflyPdf
|
|
4
4
|
module Analysers
|
5
5
|
class PdfProperties
|
6
6
|
|
7
|
-
def call content
|
8
|
-
spreads =
|
7
|
+
def call content
|
8
|
+
spreads = content.meta['spreads'] || false
|
9
9
|
|
10
10
|
pdf = PDF::Reader.new(content.file)
|
11
11
|
|
12
12
|
{
|
13
|
+
aspect_ratios: aspect_ratios(pdf, spreads),
|
14
|
+
heights: heights(pdf, spreads),
|
15
|
+
info: pdf.info,
|
13
16
|
page_count: page_count(pdf, spreads),
|
14
|
-
spread_count: spread_count(pdf, spreads),
|
15
17
|
page_numbers: page_numbers(pdf, spreads),
|
16
|
-
|
17
|
-
|
18
|
-
aspect_ratios: aspect_ratios(pdf, spreads),
|
19
|
-
info: pdf.info
|
18
|
+
spread_count: spread_count(pdf, spreads),
|
19
|
+
widths: widths(pdf, spreads)
|
20
20
|
}
|
21
21
|
end
|
22
22
|
|
data/lib/dragonfly_pdf/plugin.rb
CHANGED
@@ -24,11 +24,11 @@ module DragonflyPdf
|
|
24
24
|
app.add_analyser :widths do |content|
|
25
25
|
content.analyse(:pdf_properties)[:widths]
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
app.add_analyser :heights do |content|
|
29
29
|
content.analyse(:pdf_properties)[:heights]
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
32
|
app.add_analyser :aspect_ratios do |content|
|
33
33
|
attrs = content.analyse(:pdf_properties)[:aspect_ratios]
|
34
34
|
end
|
@@ -36,9 +36,9 @@ module DragonflyPdf
|
|
36
36
|
app.add_analyser :info do |content|
|
37
37
|
attrs = content.analyse(:pdf_properties)[:info]
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
40
|
# ---------------------------------------------------------------------
|
41
|
-
|
41
|
+
|
42
42
|
app.add_processor :page_thumb, DragonflyPdf::Processors::PageThumb.new
|
43
43
|
app.add_processor :page, DragonflyPdf::Processors::Page.new
|
44
44
|
end
|
@@ -7,11 +7,11 @@ module DragonflyPdf
|
|
7
7
|
class Page
|
8
8
|
|
9
9
|
def call content, page_number=1, opts={}
|
10
|
-
spreads =
|
10
|
+
spreads = content.meta['spreads'] || false
|
11
11
|
pdf_page_number = page_number
|
12
12
|
crop_args = ''
|
13
13
|
|
14
|
-
pdf_properties = DragonflyPdf::Analysers::PdfProperties.new.call(content
|
14
|
+
pdf_properties = DragonflyPdf::Analysers::PdfProperties.new.call(content)
|
15
15
|
|
16
16
|
raise DragonflyPdf::PageNotFound unless pdf_properties[:page_numbers].flatten.include?(page_number)
|
17
17
|
|
@@ -7,12 +7,12 @@ module DragonflyPdf
|
|
7
7
|
def call content, page_number=1, opts={}
|
8
8
|
format = opts.fetch(:format, :png)
|
9
9
|
density = opts.fetch(:density, 600)
|
10
|
-
spreads =
|
10
|
+
spreads = content.meta['spreads'] || false
|
11
11
|
|
12
12
|
args = "-alpha deactivate -background white -colorspace sRGB -density #{density}x#{density} -define pdf:use-cropbox=true -define pdf:use-trimbox=true"
|
13
13
|
crop_args = ''
|
14
14
|
|
15
|
-
pdf_properties = DragonflyPdf::Analysers::PdfProperties.new.call(content
|
15
|
+
pdf_properties = DragonflyPdf::Analysers::PdfProperties.new.call(content)
|
16
16
|
|
17
17
|
raise DragonflyPdf::PageNotFound unless pdf_properties[:page_numbers].flatten.include?(page_number)
|
18
18
|
|
@@ -35,7 +35,7 @@ module DragonflyPdf
|
|
35
35
|
content.meta['format'] = format.to_s
|
36
36
|
content.ext = format
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
def update_url attrs, args='', opts={}
|
40
40
|
format = opts['format']
|
41
41
|
attrs.ext = format if format
|
@@ -13,6 +13,13 @@ module DragonflyPdf
|
|
13
13
|
let(:spreads_cover) { app.fetch_file(SAMPLES_DIR.join('sample_spreads_cover.pdf')) }
|
14
14
|
let(:spreads_cover_back) { app.fetch_file(SAMPLES_DIR.join('sample_spreads_cover_back.pdf')) }
|
15
15
|
|
16
|
+
before do
|
17
|
+
spreads.meta['spreads'] = true
|
18
|
+
spreads_cover.meta['spreads'] = true
|
19
|
+
spreads_back.meta['spreads'] = true
|
20
|
+
spreads_cover_back.meta['spreads'] = true
|
21
|
+
end
|
22
|
+
|
16
23
|
describe 'call' do
|
17
24
|
let(:pdf_properties) { analyser.call(single_pages) }
|
18
25
|
|
@@ -32,25 +39,25 @@ module DragonflyPdf
|
|
32
39
|
|
33
40
|
describe 'for PDF with spreads' do
|
34
41
|
it 'returns two-dimensional array' do
|
35
|
-
analyser.call(spreads
|
42
|
+
analyser.call(spreads)[:page_numbers].must_equal [[1,2],[3,4],[5,6],[7,8]]
|
36
43
|
end
|
37
44
|
end
|
38
45
|
|
39
46
|
describe 'for PDF with spreads and a cover' do
|
40
47
|
it 'returns two-dimensional array' do
|
41
|
-
analyser.call(spreads_cover
|
48
|
+
analyser.call(spreads_cover)[:page_numbers].must_equal [[1],[2,3],[4,5],[6,7],[8,9]]
|
42
49
|
end
|
43
50
|
end
|
44
51
|
|
45
52
|
describe 'for PDF with spreads and a back cover' do
|
46
53
|
it 'returns two-dimensional array' do
|
47
|
-
analyser.call(spreads_back
|
54
|
+
analyser.call(spreads_back)[:page_numbers].must_equal [[1,2],[3,4],[5,6],[7,8],[9]]
|
48
55
|
end
|
49
56
|
end
|
50
57
|
|
51
58
|
describe 'for PDF with spreads and a front and a back cover' do
|
52
59
|
it 'returns two-dimensional array' do
|
53
|
-
analyser.call(spreads_cover_back
|
60
|
+
analyser.call(spreads_cover_back)[:page_numbers].must_equal [[1],[2,3],[4,5],[6,7],[8,9],[10]]
|
54
61
|
end
|
55
62
|
end
|
56
63
|
end
|
@@ -66,25 +73,25 @@ module DragonflyPdf
|
|
66
73
|
|
67
74
|
describe 'for PDF with spreads' do
|
68
75
|
it 'returns correct page count' do
|
69
|
-
analyser.call(spreads
|
76
|
+
analyser.call(spreads)[:page_count].must_equal 8
|
70
77
|
end
|
71
78
|
end
|
72
79
|
|
73
80
|
describe 'for PDF with spreads and a cover' do
|
74
81
|
it 'returns correct page count' do
|
75
|
-
analyser.call(spreads_cover
|
82
|
+
analyser.call(spreads_cover)[:page_count].must_equal 9
|
76
83
|
end
|
77
84
|
end
|
78
85
|
|
79
86
|
describe 'for PDF with spreads and a back cover' do
|
80
87
|
it 'returns correct page count' do
|
81
|
-
analyser.call(spreads_back
|
88
|
+
analyser.call(spreads_back)[:page_count].must_equal 9
|
82
89
|
end
|
83
90
|
end
|
84
91
|
|
85
92
|
describe 'for PDF with spreads and a front and a back cover' do
|
86
93
|
it 'returns correct page count' do
|
87
|
-
analyser.call(spreads_cover_back
|
94
|
+
analyser.call(spreads_cover_back)[:page_count].must_equal 10
|
88
95
|
end
|
89
96
|
end
|
90
97
|
end
|
@@ -100,25 +107,25 @@ module DragonflyPdf
|
|
100
107
|
|
101
108
|
describe 'for PDF with spreads' do
|
102
109
|
it 'returns correct page count' do
|
103
|
-
analyser.call(spreads
|
110
|
+
analyser.call(spreads)[:spread_count].must_equal 4
|
104
111
|
end
|
105
112
|
end
|
106
113
|
|
107
114
|
describe 'for PDF with spreads and a cover' do
|
108
115
|
it 'returns correct page count' do
|
109
|
-
analyser.call(spreads_cover
|
116
|
+
analyser.call(spreads_cover)[:spread_count].must_equal 5
|
110
117
|
end
|
111
118
|
end
|
112
119
|
|
113
120
|
describe 'for PDF with spreads and a back cover' do
|
114
121
|
it 'returns correct page count' do
|
115
|
-
analyser.call(spreads_back
|
122
|
+
analyser.call(spreads_back)[:spread_count].must_equal 5
|
116
123
|
end
|
117
124
|
end
|
118
125
|
|
119
126
|
describe 'for PDF with spreads and a front and a back cover' do
|
120
127
|
it 'returns correct page count' do
|
121
|
-
analyser.call(spreads_cover_back
|
128
|
+
analyser.call(spreads_cover_back)[:spread_count].must_equal 6
|
122
129
|
end
|
123
130
|
end
|
124
131
|
end
|
@@ -134,25 +141,25 @@ module DragonflyPdf
|
|
134
141
|
|
135
142
|
describe 'for PDF with spreads' do
|
136
143
|
it 'returns widths' do
|
137
|
-
analyser.call(spreads
|
144
|
+
analyser.call(spreads)[:widths].must_equal [[210.0, 210.0], [210.0, 210.0], [210.0, 210.0], [210.0, 210.0]]
|
138
145
|
end
|
139
146
|
end
|
140
147
|
|
141
148
|
describe 'for PDF with spreads and a cover' do
|
142
149
|
it 'returns correct widths' do
|
143
|
-
analyser.call(spreads_cover
|
150
|
+
analyser.call(spreads_cover)[:widths].must_equal [[210.0], [210.0, 210.0], [210.0, 210.0], [210.0, 210.0], [210.0, 210.0]]
|
144
151
|
end
|
145
152
|
end
|
146
153
|
|
147
154
|
describe 'for PDF with spreads and a back cover' do
|
148
155
|
it 'returns correct widths' do
|
149
|
-
analyser.call(spreads_back
|
156
|
+
analyser.call(spreads_back)[:widths].must_equal [[210.0, 210.0], [210.0, 210.0], [210.0, 210.0], [210.0, 210.0], [210.0]]
|
150
157
|
end
|
151
158
|
end
|
152
159
|
|
153
160
|
describe 'for PDF with spreads and a front and a back cover' do
|
154
161
|
it 'returns correct widths' do
|
155
|
-
analyser.call(spreads_cover_back
|
162
|
+
analyser.call(spreads_cover_back)[:widths].must_equal [[210.0], [210.0, 210.0], [210.0, 210.0], [210.0, 210.0], [210.0, 210.0], [210.0]]
|
156
163
|
end
|
157
164
|
end
|
158
165
|
end
|
@@ -168,25 +175,25 @@ module DragonflyPdf
|
|
168
175
|
|
169
176
|
describe 'for PDF with spreads' do
|
170
177
|
it 'returns heights' do
|
171
|
-
analyser.call(spreads
|
178
|
+
analyser.call(spreads)[:heights].must_equal [[297.0, 297.0], [297.0, 297.0], [297.0, 297.0], [297.0, 297.0]]
|
172
179
|
end
|
173
180
|
end
|
174
181
|
|
175
182
|
describe 'for PDF with spreads and a cover' do
|
176
183
|
it 'returns correct heights' do
|
177
|
-
analyser.call(spreads_cover
|
184
|
+
analyser.call(spreads_cover)[:heights].must_equal [[297.0], [297.0, 297.0], [297.0, 297.0], [297.0, 297.0], [297.0, 297.0]]
|
178
185
|
end
|
179
186
|
end
|
180
187
|
|
181
188
|
describe 'for PDF with spreads and a back cover' do
|
182
189
|
it 'returns correct heights' do
|
183
|
-
analyser.call(spreads_back
|
190
|
+
analyser.call(spreads_back)[:heights].must_equal [[297.0, 297.0], [297.0, 297.0], [297.0, 297.0], [297.0, 297.0], [297.0]]
|
184
191
|
end
|
185
192
|
end
|
186
193
|
|
187
194
|
describe 'for PDF with spreads and a front and a back cover' do
|
188
195
|
it 'returns correct heights' do
|
189
|
-
analyser.call(spreads_cover_back
|
196
|
+
analyser.call(spreads_cover_back)[:heights].must_equal [[297.0], [297.0, 297.0], [297.0, 297.0], [297.0, 297.0], [297.0, 297.0], [297.0]]
|
190
197
|
end
|
191
198
|
end
|
192
199
|
end
|
@@ -202,25 +209,25 @@ module DragonflyPdf
|
|
202
209
|
|
203
210
|
describe 'for PDF with spreads' do
|
204
211
|
it 'returns aspect ratios' do
|
205
|
-
analyser.call(spreads
|
212
|
+
analyser.call(spreads)[:aspect_ratios].map{ |i| i.is_a?(Array) ? i.map{ |j| j.round(2) } : i.round(2) }.must_equal [[0.71, 0.71], [0.71, 0.71], [0.71, 0.71], [0.71, 0.71]]
|
206
213
|
end
|
207
214
|
end
|
208
215
|
|
209
216
|
describe 'for PDF with spreads and a cover' do
|
210
217
|
it 'returns correct aspect ratios' do
|
211
|
-
analyser.call(spreads_cover
|
218
|
+
analyser.call(spreads_cover)[:aspect_ratios].map{ |i| i.is_a?(Array) ? i.map{ |j| j.round(2) } : i.round(2) }.must_equal [[0.71], [0.71, 0.71], [0.71, 0.71], [0.71, 0.71], [0.71, 0.71]]
|
212
219
|
end
|
213
220
|
end
|
214
221
|
|
215
222
|
describe 'for PDF with spreads and a back cover' do
|
216
223
|
it 'returns correct aspect ratios' do
|
217
|
-
analyser.call(spreads_back
|
224
|
+
analyser.call(spreads_back)[:aspect_ratios].map{ |i| i.is_a?(Array) ? i.map{ |j| j.round(2) } : i.round(2) }.must_equal [[0.71, 0.71], [0.71, 0.71], [0.71, 0.71], [0.71, 0.71], [0.71]]
|
218
225
|
end
|
219
226
|
end
|
220
227
|
|
221
228
|
describe 'for PDF with spreads and a front and a back cover' do
|
222
229
|
it 'returns correct aspect ratios' do
|
223
|
-
analyser.call(spreads_cover_back
|
230
|
+
analyser.call(spreads_cover_back)[:aspect_ratios].map{ |i| i.is_a?(Array) ? i.map{ |j| j.round(2) } : i.round(2) }.must_equal [[0.71], [0.71, 0.71], [0.71, 0.71], [0.71, 0.71], [0.71, 0.71], [0.71]]
|
224
231
|
end
|
225
232
|
end
|
226
233
|
end
|
@@ -9,6 +9,12 @@ module DragonflyPdf
|
|
9
9
|
# ---------------------------------------------------------------------
|
10
10
|
|
11
11
|
describe 'analysers' do
|
12
|
+
it 'adds #pdf_properties' do
|
13
|
+
pdf.must_respond_to :pdf_properties
|
14
|
+
end
|
15
|
+
it 'allows an options parameter on #pdf_properties' do
|
16
|
+
pdf.pdf_properties.must_be_kind_of Hash
|
17
|
+
end
|
12
18
|
it 'adds #page_count' do
|
13
19
|
pdf.must_respond_to :page_count
|
14
20
|
end
|
@@ -32,9 +38,8 @@ module DragonflyPdf
|
|
32
38
|
end
|
33
39
|
end
|
34
40
|
|
35
|
-
|
36
41
|
# ---------------------------------------------------------------------
|
37
|
-
|
42
|
+
|
38
43
|
describe 'processors' do
|
39
44
|
it 'adds #page' do
|
40
45
|
pdf.must_respond_to :page
|
@@ -14,6 +14,13 @@ module DragonflyPdf
|
|
14
14
|
let(:spreads_cover) { Dragonfly::Content.new(app, SAMPLES_DIR.join('sample_spreads_cover.pdf')) }
|
15
15
|
let(:spreads_cover_back) { Dragonfly::Content.new(app, SAMPLES_DIR.join('sample_spreads_cover_back.pdf')) }
|
16
16
|
|
17
|
+
before do
|
18
|
+
spreads.meta['spreads'] = true
|
19
|
+
spreads_cover.meta['spreads'] = true
|
20
|
+
spreads_back.meta['spreads'] = true
|
21
|
+
spreads_cover_back.meta['spreads'] = true
|
22
|
+
end
|
23
|
+
|
17
24
|
# =====================================================================
|
18
25
|
|
19
26
|
it 'returns PDF by default' do
|
@@ -14,6 +14,15 @@ module DragonflyPdf
|
|
14
14
|
let(:spreads_cover) { Dragonfly::Content.new(app, SAMPLES_DIR.join('sample_spreads_cover.pdf')) }
|
15
15
|
let(:spreads_cover_back) { Dragonfly::Content.new(app, SAMPLES_DIR.join('sample_spreads_cover_back.pdf')) }
|
16
16
|
|
17
|
+
before do
|
18
|
+
spreads.meta['spreads'] = true
|
19
|
+
spreads_cover.meta['spreads'] = true
|
20
|
+
spreads_back.meta['spreads'] = true
|
21
|
+
spreads_cover_back.meta['spreads'] = true
|
22
|
+
end
|
23
|
+
|
24
|
+
# =====================================================================
|
25
|
+
|
17
26
|
it 'returns PNG by default' do
|
18
27
|
processor.call(single_pages, 1, density: 72)
|
19
28
|
get_mime_type(single_pages.path).must_include "image/png"
|
@@ -62,7 +71,7 @@ module DragonflyPdf
|
|
62
71
|
end
|
63
72
|
|
64
73
|
# ---------------------------------------------------------------------
|
65
|
-
|
74
|
+
|
66
75
|
def get_mime_type file_path
|
67
76
|
`file --mime-type #{file_path}`.gsub(/\n/, "")
|
68
77
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dragonfly_pdf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tomas Celizna
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-01-
|
11
|
+
date: 2015-01-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dragonfly
|