vips 8.6.3

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.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.travis.yml +47 -0
  4. data/.yardopts +2 -0
  5. data/Gemfile +4 -0
  6. data/README.md +64 -0
  7. data/Rakefile +28 -0
  8. data/example/annotate.rb +17 -0
  9. data/example/daltonize8.rb +75 -0
  10. data/example/example1.rb +12 -0
  11. data/example/example2.rb +34 -0
  12. data/example/example3.rb +19 -0
  13. data/example/example4.rb +18 -0
  14. data/example/example5.rb +31 -0
  15. data/example/inheritance_with_refcount.rb +286 -0
  16. data/example/thumb.rb +31 -0
  17. data/example/trim8.rb +41 -0
  18. data/example/watermark.rb +44 -0
  19. data/example/wobble.rb +36 -0
  20. data/ext/Rakefile +35 -0
  21. data/lib/vips.rb +597 -0
  22. data/lib/vips/access.rb +11 -0
  23. data/lib/vips/align.rb +11 -0
  24. data/lib/vips/angle.rb +12 -0
  25. data/lib/vips/angle45.rb +16 -0
  26. data/lib/vips/bandformat.rb +20 -0
  27. data/lib/vips/coding.rb +14 -0
  28. data/lib/vips/compass_direction.rb +17 -0
  29. data/lib/vips/direction.rb +11 -0
  30. data/lib/vips/extend.rb +17 -0
  31. data/lib/vips/gobject.rb +122 -0
  32. data/lib/vips/gvalue.rb +281 -0
  33. data/lib/vips/image.rb +1500 -0
  34. data/lib/vips/interesting.rb +14 -0
  35. data/lib/vips/interpolate.rb +62 -0
  36. data/lib/vips/interpretation.rb +28 -0
  37. data/lib/vips/kernel.rb +22 -0
  38. data/lib/vips/methods.rb +2145 -0
  39. data/lib/vips/object.rb +244 -0
  40. data/lib/vips/operation.rb +365 -0
  41. data/lib/vips/operationboolean.rb +14 -0
  42. data/lib/vips/operationcomplex.rb +12 -0
  43. data/lib/vips/operationcomplex2.rb +10 -0
  44. data/lib/vips/operationcomplexget.rb +11 -0
  45. data/lib/vips/operationmath.rb +18 -0
  46. data/lib/vips/operationmath2.rb +10 -0
  47. data/lib/vips/operationrelational.rb +15 -0
  48. data/lib/vips/operationround.rb +11 -0
  49. data/lib/vips/size.rb +13 -0
  50. data/lib/vips/version.rb +4 -0
  51. data/vips.gemspec +36 -0
  52. metadata +209 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 17ebdb3047de6d3b6982f72e06bcb58dbadd39af057918e601970818646b4007
4
+ data.tar.gz: ecd94b19ffba51de569bdf7bd58398b9b23cd05dc5e617e08ca0508cafb8099d
5
+ SHA512:
6
+ metadata.gz: 7587de2d7115ab17b0af59e4cbd304ceff1a9a3c94d8448a6850a07b9296f7291dcd5ce89f35c0bba912cc7049401a6c05457c49765ff727688f4948fdd682c6
7
+ data.tar.gz: e80bd5ba9216eb25f167ae2aa5a1b3328f603688bacdea269ed78b7620fd2689775e2614f2aca76a9f18851445f936cf53fc9a9dbb53f7040e93676c22734323
@@ -0,0 +1,16 @@
1
+ .yardoc
2
+ *.swp
3
+ doc
4
+ pkg/*.gem
5
+
6
+ # skip Gemfile.lock since this is a gem
7
+ Gemfile.lock
8
+
9
+ /bin/
10
+ /include/
11
+ /share/
12
+ /lib/lib*
13
+ /lib/girepository-1.0
14
+ /lib/pkgconfig
15
+
16
+ /ext/vips-*
@@ -0,0 +1,47 @@
1
+ sudo: false
2
+
3
+ addons:
4
+ apt:
5
+ packages:
6
+ - libexpat1-dev
7
+ - gettext
8
+ - liblcms2-dev
9
+ - libmagickwand-dev
10
+ - libopenexr-dev
11
+ - libcfitsio3-dev
12
+ - libgif-dev
13
+ - libgs-dev
14
+ - libgsf-1-dev
15
+ - libmatio-dev
16
+ - libopenslide-dev
17
+ - liborc-0.4-dev
18
+ - libpango1.0-dev
19
+ - libpoppler-glib-dev
20
+ - librsvg2-dev
21
+ - libwebp-dev
22
+ # missing on trusty, unfortunately
23
+ # - libwebpmux2
24
+ - libfftw3-dev
25
+ - libglib2.0-dev
26
+
27
+ cache:
28
+ bundler: true
29
+ directories: $HOME/vips/ext
30
+
31
+ language: ruby
32
+ rvm:
33
+ - 2.3
34
+ - 2.4
35
+ - 2.5
36
+ - 2.6
37
+
38
+ before_script:
39
+ - gem update --system
40
+ - gem install bundler
41
+ - bundle exec rake ext
42
+
43
+ script:
44
+ - bundle exec rake
45
+
46
+ gemfile:
47
+ - Gemfile
@@ -0,0 +1,2 @@
1
+ --markup-provider=redcarpet
2
+ --markup=markdown
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # all gems are handled by .gemspec (since this repo is for a gem)
4
+ gemspec
@@ -0,0 +1,64 @@
1
+ # Vips
2
+
3
+ This gem is a backwards compatible fork of `ruby-vips` but also includes (and compiles) the [libvips] source code.
4
+
5
+ [![Build Status](https://secure.travis-ci.org/ioquatix/vips.svg)](http://travis-ci.org/ioquatix/vips)
6
+
7
+ [libvips]: https://jcupitt.github.io/libvips
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'vips'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install vips
24
+
25
+ You'll still need to install `glib` and `gobject-introspection`.
26
+
27
+ ## Usage
28
+
29
+ Exactly the same way as [ruby-vips].
30
+
31
+ [ruby-vips]: https://github.com/jcupitt/ruby-vips
32
+
33
+ ## Contributing
34
+
35
+ 1. Fork it
36
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
37
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
38
+ 4. Push to the branch (`git push origin my-new-feature`)
39
+ 5. Create new Pull Request
40
+
41
+ ## License
42
+
43
+ Released under the MIT license.
44
+
45
+ Copyright, 2014, by John Cupitt.
46
+ Copyright, 2017, by [Samuel G. D. Williams](http://www.codeotaku.com/samuel-williams).
47
+
48
+ Permission is hereby granted, free of charge, to any person obtaining a copy
49
+ of this software and associated documentation files (the "Software"), to deal
50
+ in the Software without restriction, including without limitation the rights
51
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
52
+ copies of the Software, and to permit persons to whom the Software is
53
+ furnished to do so, subject to the following conditions:
54
+
55
+ The above copyright notice and this permission notice shall be included in
56
+ all copies or substantial portions of the Software.
57
+
58
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
61
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
62
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
63
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
64
+ THE SOFTWARE.
@@ -0,0 +1,28 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:test)
5
+
6
+ task :default => :test
7
+
8
+ task :ext do
9
+ Dir.chdir "ext" do
10
+ sh "rake"
11
+ end
12
+ end
13
+
14
+ task :console do
15
+ require 'pry'
16
+
17
+ require_relative 'lib/vips'
18
+
19
+ Pry.start
20
+ end
21
+
22
+ require "yard/rake/yardoc_task"
23
+
24
+ YARD::Rake::YardocTask.new do |yard|
25
+ require "yard"
26
+ require "github/markup"
27
+ require "redcarpet"
28
+ end
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'vips'
4
+
5
+ im = Vips::Image.new_from_file ARGV[0], :access => :sequential
6
+
7
+ left_text = Vips::Image.text "left corner", :dpi => 300
8
+ left = left_text.embed 50, 50, im.width, 150
9
+
10
+ right_text = Vips::Image.text "right corner", :dpi => 300
11
+ right = right_text.embed im.width - right_text.width - 50, 50, im.width, 150
12
+
13
+ footer = (left | right).ifthenelse(0, [255, 0, 0], :blend => true)
14
+
15
+ im = im.insert footer, 0, im.height, :expand => true
16
+
17
+ im.write_to_file ARGV[1]
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/ruby
2
+
3
+ # daltonize an image with ruby-vips
4
+ # based on
5
+ # http://scien.stanford.edu/pages/labsite/2005/psych221/projects/05/ofidaner/colorblindness_project.htm
6
+ # see
7
+ # http://libvips.blogspot.co.uk/2013/05/daltonize-in-ruby-vips-carrierwave-and.html
8
+ # for a discussion of this code
9
+
10
+ require 'vips'
11
+
12
+ #Vips.set_debug true
13
+
14
+ # matrices to convert D65 XYZ to and from bradford cone space
15
+ xyz_to_brad = [
16
+ [0.8951, 0.2664, -0.1614],
17
+ [-0.7502, 1.7135, 0.0367],
18
+ [0.0389, -0.0685, 1.0296]
19
+ ]
20
+ brad_to_xyz = [
21
+ [0.987, -0.147, 0.16],
22
+ [0.432, 0.5184, 0.0493],
23
+ [-0.0085, 0.04, 0.968]
24
+ ]
25
+
26
+ im = Vips::Image.new_from_file ARGV[0]
27
+
28
+ # remove any alpha channel before processing
29
+ alpha = nil
30
+ if im.bands == 4
31
+ alpha = im[3]
32
+ im = im.extract_band 0, :n => 3
33
+ end
34
+
35
+ begin
36
+ # import to XYZ with lcms
37
+ # if there's no profile there, we'll fall back to the thing below
38
+ xyz = im.icc_import :embedded => true, :pcs => :xyz
39
+ rescue Vips::Error
40
+ # nope .. use the built-in converter instead
41
+ xyz = im.colourspace :xyz
42
+ end
43
+
44
+ brad = xyz.recomb xyz_to_brad
45
+
46
+ # through the Deuteranope matrix
47
+ # we need rows to sum to 1 in Bradford space --- the matrix in the original
48
+ # Python code sums to 1.742
49
+ deut = brad.recomb [
50
+ [1, 0, 0],
51
+ [0.7, 0, 0.3],
52
+ [0, 0, 1]
53
+ ]
54
+
55
+ xyz = deut.recomb brad_to_xyz
56
+
57
+ # .. and back to sRGB
58
+ rgb = xyz.colourspace :srgb
59
+
60
+ # so this is the colour error
61
+ err = im - rgb
62
+
63
+ # add the error back to other channels to make a compensated image
64
+ im = im + err.recomb([
65
+ [0, 0, 0],
66
+ [0.7, 1, 0],
67
+ [0.7, 0, 1]
68
+ ])
69
+
70
+ # reattach any alpha we saved above
71
+ if alpha
72
+ im = im.bandjoin(alpha)
73
+ end
74
+
75
+ im.write_to_file ARGV[1]
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'logger'
4
+ require 'vips'
5
+
6
+ GLib::logger.level = Logger::DEBUG
7
+
8
+ op = Vips::Operation.new "black"
9
+
10
+ op = nil
11
+ GC.start
12
+ Vips::Operation.print_all
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'logger'
4
+ require 'vips'
5
+
6
+ puts ""
7
+ puts "starting up:"
8
+
9
+ # this makes vips keep a list of all active objects which we can print out
10
+ Vips::leak_set true
11
+
12
+ # disable the operation cache
13
+ Vips::cache_set_max 0
14
+
15
+ # GLib::logger.level = Logger::DEBUG
16
+
17
+ n = 10000
18
+
19
+ n.times do |i|
20
+ puts ""
21
+ puts "call #{i} ..."
22
+ out = Vips::Operation.call "black", [200, 300]
23
+ if out.width != 200 or out.height != 300
24
+ puts "bad image result from black"
25
+ end
26
+ end
27
+
28
+ puts ""
29
+ puts "after #{n} calls:"
30
+ GC.start
31
+ Vips::Object::print_all
32
+
33
+ puts ""
34
+ puts "shutting down:"
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'vips'
4
+
5
+ # this makes vips keep a list of all active objects
6
+ Vips::leak_set true
7
+
8
+ # disable the operation cache
9
+ # Vips::cache_set_max 0
10
+
11
+ # turn on debug logging
12
+ GLib::logger.level = Logger::DEBUG
13
+
14
+ 1.times do |i|
15
+ puts "loop #{i} ..."
16
+ im = Vips::Image.new_from_file ARGV[0]
17
+ im = im.embed 100, 100, 3000, 3000, :extend => :mirror
18
+ im.write_to_file "x.v"
19
+ end
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'vips'
4
+
5
+ # this makes vips keep a list of all active objects
6
+ Vips::leak_set true
7
+
8
+ # disable the operation cache
9
+ #Vips::cache_set_max 0
10
+
11
+ # turn on debug logging
12
+ #Vips.set_debug true
13
+
14
+ ARGV.each do |filename|
15
+ im = Vips::Image.new_from_file filename
16
+ profile = im.get_value "icc-profile-data"
17
+ puts "profile has #{profile.length} bytes"
18
+ end
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'vips'
4
+
5
+ # this makes vips keep a list of all active objects
6
+ # Vips::leak_set true
7
+
8
+ # disable the operation cache
9
+ # Vips::cache_set_max 0
10
+
11
+ # turn on debug logging
12
+ #Vips.set_debug true
13
+
14
+ if ARGV.length < 2
15
+ raise "usage: #{$PROGRAM_NAME}: input-file output-file"
16
+ end
17
+
18
+ im = Vips::Image.new_from_file ARGV[0], :access => :sequential
19
+
20
+ im *= [1, 2, 1]
21
+
22
+ # we want to be able to specify a scale for the convolution mask, so we have to
23
+ # make it ourselves
24
+ # if you are OK with scale=1, you can just pass the array directly to .conv()
25
+ mask = Vips::Image.new_from_array [
26
+ [-1, -1, -1],
27
+ [-1, 16, -1],
28
+ [-1, -1, -1]], 8
29
+ im = im.conv mask
30
+
31
+ im.write_to_file ARGV[1]
@@ -0,0 +1,286 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'ffi'
4
+ require 'forwardable'
5
+
6
+ # this is really very crude logging
7
+
8
+ # @private
9
+ $vips_debug = true
10
+
11
+ # @private
12
+ def log str
13
+ if $vips_debug
14
+ puts str
15
+ end
16
+ end
17
+
18
+ def set_debug debug
19
+ $vips_debug = debug
20
+ end
21
+
22
+ module Libc
23
+ extend FFI::Library
24
+ ffi_lib FFI::Library::LIBC
25
+
26
+ attach_function :malloc, [:size_t], :pointer
27
+ attach_function :free, [:pointer], :void
28
+ end
29
+
30
+ module GLib
31
+ extend FFI::Library
32
+ ffi_lib 'gobject-2.0'
33
+
34
+ # nil being the default
35
+ glib_log_domain = nil
36
+
37
+ def self.set_log_domain(domain)
38
+ glib_log_domain = domain
39
+ end
40
+
41
+ # we have a set of things we need to inherit in different ways:
42
+ #
43
+ # - we want to be able to subclass GObject in a simple way
44
+ # - the layouts of the nested structs
45
+ # - casting between structs which share a base
46
+ # - gobject refcounting
47
+ #
48
+ # the solution is to split the class into four areas which we treat
49
+ # differently:
50
+ #
51
+ # - we have a "wrapper" Ruby class to allow easy subclassing ... this has a
52
+ # @struct member which holds the actual pointer
53
+ # - we use "forwardable" to forward the various ffi methods on to the
54
+ # @struct member ... we arrange things so that subclasses do not need to
55
+ # do the forwarding themselves
56
+ # - we have two versions of the struct: a plain one which we can use for
57
+ # casting that will not change the refcounts
58
+ # - and a managed one with an unref which we just use for .new
59
+ # - we separate the struct layout into a separate module to avoid repeating
60
+ # ourselves
61
+
62
+ class GObject
63
+ extend Forwardable
64
+ extend SingleForwardable
65
+
66
+ def_instance_delegators :@struct, :[], :to_ptr
67
+ def_single_delegators :ffi_struct, :ptr
68
+
69
+ # the layout of the GObject struct
70
+ module GObjectLayout
71
+ def self.included(base)
72
+ base.class_eval do
73
+ layout :g_type_instance, :pointer,
74
+ :ref_count, :uint,
75
+ :qdata, :pointer
76
+ end
77
+ end
78
+ end
79
+
80
+ # the struct with unref ... manage object lifetime with this
81
+ class ManagedStruct < FFI::ManagedStruct
82
+ include GObjectLayout
83
+
84
+ def initialize(ptr)
85
+ log "GLib::GObject::ManagedStruct.new: #{ptr}"
86
+ super
87
+ end
88
+
89
+ def self.release(ptr)
90
+ log "GLib::GObject::ManagedStruct.release: unreffing #{ptr}"
91
+ GLib::g_object_unref(ptr) unless ptr.null?
92
+ end
93
+
94
+ end
95
+
96
+ # the plain struct ... cast with this
97
+ class Struct < FFI::Struct
98
+ include GObjectLayout
99
+
100
+ def initialize(ptr)
101
+ log "GLib::GObject::Struct.new: #{ptr}"
102
+ super
103
+ end
104
+
105
+ end
106
+
107
+ # don't allow ptr == nil, we never want to allocate a GObject struct
108
+ # ourselves, we just want to wrap GLib-allocated GObjects
109
+ #
110
+ # here we use ManagedStruct, not Struct, since this is the ref that will
111
+ # need the unref
112
+ def initialize(ptr)
113
+ log "GLib::GObject.initialize: ptr = #{ptr}"
114
+ @struct = ffi_managed_struct.new(ptr)
115
+ end
116
+
117
+ # access to the cast struct for this class
118
+ def ffi_struct
119
+ self.class.ffi_struct
120
+ end
121
+
122
+ class << self
123
+ def ffi_struct
124
+ self.const_get(:Struct)
125
+ end
126
+ end
127
+
128
+ # access to the lifetime managed struct for this class
129
+ def ffi_managed_struct
130
+ self.class.ffi_managed_struct
131
+ end
132
+
133
+ class << self
134
+ def ffi_managed_struct
135
+ self.const_get(:ManagedStruct)
136
+ end
137
+ end
138
+
139
+ end
140
+
141
+ # :gtype will usually be 64-bit, but will be 32-bit on 32-bit Windows
142
+ typedef :ulong, :GType
143
+
144
+ end
145
+
146
+ module Vips
147
+ extend FFI::Library
148
+ ffi_lib 'vips'
149
+
150
+ LOG_DOMAIN = "VIPS"
151
+ GLib::set_log_domain(LOG_DOMAIN)
152
+
153
+ # need to repeat this
154
+ typedef :ulong, :GType
155
+
156
+ attach_function :vips_init, [:string], :int
157
+ attach_function :vips_shutdown, [], :void
158
+
159
+ attach_function :vips_error_buffer, [], :string
160
+ attach_function :vips_error_clear, [], :void
161
+
162
+ def self.get_error
163
+ errstr = Vips::vips_error_buffer
164
+ Vips::vips_error_clear
165
+ errstr
166
+ end
167
+
168
+ if Vips::vips_init($0) != 0
169
+ puts Vips::get_error
170
+ exit 1
171
+ end
172
+
173
+ at_exit {
174
+ Vips::vips_shutdown
175
+ }
176
+
177
+ attach_function :vips_object_print_all, [], :void
178
+ attach_function :vips_leak_set, [:int], :void
179
+
180
+ def self.showall
181
+ if $vips_debug
182
+ GC.start
183
+ vips_object_print_all
184
+ end
185
+ end
186
+
187
+ if $vips_debug
188
+ vips_leak_set 1
189
+ end
190
+
191
+ class VipsObject < GLib::GObject
192
+
193
+ # the layout of the VipsObject struct
194
+ module VipsObjectLayout
195
+ def self.included(base)
196
+ base.class_eval do
197
+ # don't actually need most of these, remove them later
198
+ layout :parent, GLib::GObject::Struct,
199
+ :constructed, :int,
200
+ :static_object, :int,
201
+ :argument_table, :pointer,
202
+ :nickname, :string,
203
+ :description, :string,
204
+ :preclose, :int,
205
+ :close, :int,
206
+ :postclose, :int,
207
+ :local_memory, :size_t
208
+ end
209
+ end
210
+ end
211
+
212
+ class Struct < GLib::GObject::Struct
213
+ include VipsObjectLayout
214
+
215
+ def initialize(ptr)
216
+ log "Vips::VipsObject::Struct.new: #{ptr}"
217
+ super
218
+ end
219
+
220
+ end
221
+
222
+ class ManagedStruct < GLib::GObject::ManagedStruct
223
+ include VipsObjectLayout
224
+
225
+ def initialize(ptr)
226
+ log "Vips::VipsObject::ManagedStruct.new: #{ptr}"
227
+ super
228
+ end
229
+
230
+ end
231
+
232
+ end
233
+
234
+ class VipsImage < VipsObject
235
+
236
+ # the layout of the VipsImage struct
237
+ module VipsImageLayout
238
+ def self.included(base)
239
+ base.class_eval do
240
+ layout :parent, VipsObject::Struct
241
+ # rest opaque
242
+ end
243
+ end
244
+ end
245
+
246
+ class Struct < VipsObject::Struct
247
+ include VipsImageLayout
248
+
249
+ def initialize(ptr)
250
+ log "Vips::VipsImage::Struct.new: #{ptr}"
251
+ super
252
+ end
253
+
254
+ end
255
+
256
+ class ManagedStruct < VipsObject::ManagedStruct
257
+ include VipsImageLayout
258
+
259
+ def initialize(ptr)
260
+ log "Vips::VipsImage::ManagedStruct.new: #{ptr}"
261
+ super
262
+ end
263
+
264
+ end
265
+
266
+ def self.new_partial
267
+ VipsImage.new(Vips::vips_image_new)
268
+ end
269
+
270
+ end
271
+
272
+ attach_function :vips_image_new, [], :pointer
273
+
274
+ end
275
+
276
+ puts "creating image"
277
+ begin
278
+ x = Vips::VipsImage.new_partial
279
+ puts "x = #{x}"
280
+ puts ""
281
+ puts "x[:parent] = #{x[:parent]}"
282
+ puts ""
283
+ puts "x[:parent][:description] = #{x[:parent][:description]}"
284
+ puts ""
285
+ end
286
+