sessionm-vast 1.0.4

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 (39) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +51 -0
  3. data/lib/vast/ad.rb +103 -0
  4. data/lib/vast/companion_creative.rb +81 -0
  5. data/lib/vast/creative.rb +62 -0
  6. data/lib/vast/document.rb +71 -0
  7. data/lib/vast/element.rb +9 -0
  8. data/lib/vast/extension.rb +18 -0
  9. data/lib/vast/icon.rb +87 -0
  10. data/lib/vast/inline_ad.rb +22 -0
  11. data/lib/vast/linear_creative.rb +57 -0
  12. data/lib/vast/mediafile.rb +56 -0
  13. data/lib/vast/non_linear_creative.rb +97 -0
  14. data/lib/vast/wrapper_ad.rb +19 -0
  15. data/lib/vast.rb +33 -0
  16. data/lib/vast3_draft.xsd +1036 -0
  17. data/lib/vast_2.0.1.xsd +643 -0
  18. data/test/ad_test.rb +122 -0
  19. data/test/companion_creative_test.rb +38 -0
  20. data/test/creative_test.rb +35 -0
  21. data/test/document_test.rb +72 -0
  22. data/test/examples/document_with_no_ads.xml +3 -0
  23. data/test/examples/document_with_one_inline_ad.xml +121 -0
  24. data/test/examples/document_with_one_inline_and_one_wrapper_ad.xml +105 -0
  25. data/test/examples/document_with_one_wrapper_ad.xml +40 -0
  26. data/test/examples/document_with_two_inline_ads.xml +120 -0
  27. data/test/examples/invalid_document.xml +3 -0
  28. data/test/examples/invalid_document_with_missing_ad_type.xml +58 -0
  29. data/test/examples/invalid_document_with_missing_creative_type.xml +39 -0
  30. data/test/examples/vast3_inline.xml +86 -0
  31. data/test/extension_test.rb +20 -0
  32. data/test/inline_ad_test.rb +14 -0
  33. data/test/linear_creative_test.rb +26 -0
  34. data/test/mediafile_test.rb +20 -0
  35. data/test/non_linear_creative_test.rb +39 -0
  36. data/test/test_helper.rb +13 -0
  37. data/test/vast3_inline_ad_test.rb +23 -0
  38. data/test/wrapper_ad_test.rb +16 -0
  39. metadata +94 -0
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Chris Dinn
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,51 @@
1
+ = VAST
2
+
3
+ A library for parsing Digital Video Ad Serving Template (VAST) 2.0 XML documents, as outlined by the Interactive Advertising Bureau at
4
+ http://www.iab.net/iab_products_and_industry_services/508676/digitalvideo/vast. VAST outlines a standard document format for communication between digital video players and ad servers, including support for
5
+ multiple forms of creative and tracking support that conforms to the latest IAB standards.
6
+
7
+ It's recommended that you review the resources made available for the IAB. Whenever possible the documentation in this library has been
8
+ pulled directly from those resources.
9
+
10
+ This library strives to be as true to the standard as possible, while presenting a Ruby-friendly interface.
11
+
12
+ == Installation
13
+
14
+ VAST is available as a RubyGem.
15
+
16
+ gem install vast
17
+
18
+ == Usage
19
+
20
+ Parse a VAST document and access its contents using an easy-to-understand model. For example:
21
+
22
+ document = VAST::Document.parse(File.read("vast_document.xml"))
23
+ inline_ad = document.inline_ads.first
24
+ puts inline_ad.linear_creative.mediafiles.first.type
25
+ => "video/x-flv"
26
+ puts inline_ad.linear_creative.mediafiles.first.url
27
+ => #<URI::HTTP:0x1015ad5f0 URL:http://creativeurl.ca/mediafile>
28
+
29
+ See the documentation for the individual classes for an overview of what information available for each class.
30
+
31
+ == Documentation
32
+
33
+ Read the rdoc at http://rdoc.info/projects/chrisdinn/vast
34
+
35
+ == Problems/Bugs/Requests
36
+
37
+ Please, file an issue.
38
+
39
+ == Note on Patches/Pull Requests
40
+
41
+ * Fork the project.
42
+ * Make your feature addition or bug fix.
43
+ * Add tests for it. This is important so I don't break it in a
44
+ future version unintentionally.
45
+ * Commit, do not mess with rakefile, version, or history.
46
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
47
+ * Send me a pull request. Bonus points for topic branches.
48
+
49
+ == Copyright
50
+
51
+ © 2010 Chris Dinn. See LICENSE for details.
data/lib/vast/ad.rb ADDED
@@ -0,0 +1,103 @@
1
+ module VAST
2
+ # Contains some combination of video, companions, and non-linear units for a single advertiser.
3
+ #
4
+ # A single VAST response may include multiple Ads from multiple advertisers. It will be up to
5
+ # the Video Player to determine the order, timing, placement, etc for the multiple ads. However,
6
+ # the player should generally respect the sequential order of the Ad elements within a VAST response.
7
+ #
8
+ # The VAST response does not contain information on the placement or timing of each ad. It is up
9
+ # to the Video Player to determine the optimal inclusion points of the ads.
10
+ #
11
+ # Can either be a InlineAd, meaning it contains all the elements necessary to display the
12
+ # visual experience, or a WrapperAd, which points to a downstream VAST document that must be
13
+ # requested from another server.
14
+ #
15
+ # An Ad may include one or more pieces of creative that are part of a single execution. For example, an Ad
16
+ # may include a linear video element with a set of companion banners; this would be reflected by two Creative
17
+ # elements, one LinearCreative and one CompanionCreative.
18
+ class Ad < Element
19
+
20
+ # Creates proper ad type
21
+ def self.create(node)
22
+ if node.at('InLine')
23
+ InlineAd.new(node)
24
+ elsif node.at('Wrapper')
25
+ WrapperAd.new(node)
26
+ else
27
+ raise InvalidAdError
28
+ end
29
+ end
30
+
31
+ # Ad id, if indicated
32
+ def id
33
+ source_node[:id]
34
+ end
35
+
36
+ def sequence
37
+ source_node[:sequence]
38
+ end
39
+
40
+ # Returns name of source ad server
41
+ def ad_system
42
+ ad_system_node = source_node.at("AdSystem")
43
+ if ad_system_node
44
+ ad_system_node.content
45
+ else
46
+ raise InvalidAdError, "missing AdSystem node in Ad"
47
+ end
48
+ end
49
+
50
+ # Returns URI to request if ad does not play due to error.
51
+ def error_url
52
+ error_url_node = source_node.at("Error")
53
+ URI.parse(URI.escape(error_url_node.content.strip)) if error_url_node
54
+ end
55
+
56
+ # Returns an array containing all linear creatives.
57
+ def linear_creatives
58
+ source_node.xpath('.//Creative/Linear').to_a.collect do |node|
59
+ LinearCreative.new(node)
60
+ end
61
+ end
62
+
63
+ # This is a convenience method for when only the first piece of linear creative is needed.
64
+ # It's common for an ad to contain only one piece of linear creative.
65
+ def linear_creative
66
+ linear_creatives.first
67
+ end
68
+
69
+ # Returns an array containing all non linear creatives.
70
+ def non_linear_creatives
71
+ source_node.xpath('.//Creative/NonLinearAds/NonLinear').to_a.collect do |node|
72
+ NonLinearCreative.new(node)
73
+ end
74
+ end
75
+
76
+ # Returns an array containing all companion creatives.
77
+ def companion_creatives
78
+ source_node.xpath('.//Creative/CompanionAds/Companion').to_a.collect do |node|
79
+ CompanionCreative.new(node)
80
+ end
81
+ end
82
+
83
+ # Each Ad must contain at least one impression.
84
+ def impression
85
+ URI.parse(URI.escape(source_node.at('Impression').content.strip))
86
+ end
87
+
88
+ # Array of all impressions available for this ad, excluding those specific
89
+ # to a particular creative.
90
+ def impressions
91
+ source_node.xpath('.//Impression').to_a.collect do |node|
92
+ URI.parse(URI.escape(node.content.strip))
93
+ end
94
+ end
95
+
96
+ # All extensions included with this ad.
97
+ def extensions
98
+ source_node.xpath('.//Extension').to_a.collect do |node|
99
+ Extension.new(node)
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,81 @@
1
+ module VAST
2
+ # Commonly text, display ads, rich media, or skins that wrap around the video experience. These ads come
3
+ # in a number of sizes and shapes and typically run alongside or surrounding the video player.
4
+ class CompanionCreative < Creative
5
+
6
+ def id
7
+ source_node[:id]
8
+ end
9
+
10
+ # Width in pixels of companion
11
+ def width
12
+ source_node[:width].to_i
13
+ end
14
+
15
+ # Height in pixels of companion
16
+ def height
17
+ source_node[:height].to_i
18
+ end
19
+
20
+ # Width in pixels of expanding companion ad when in expanded state
21
+ def expanded_width
22
+ source_node[:expandedWidth].to_i
23
+ end
24
+
25
+ # Height in pixels of expanding companion ad when in expanded state
26
+ def expanded_height
27
+ source_node[:expandedHeight].to_i
28
+ end
29
+
30
+ # Defines the method to use for communication with the companion
31
+ def api_framework
32
+ source_node[:apiFramework]
33
+ end
34
+
35
+ # URI to open as destination page when user clicks on the video
36
+ def click_through_url
37
+ URI.parse URI.escape(source_node.at('CompanionClickThrough').content.strip)
38
+ end
39
+
40
+ # Alternate text to be displayed when companion is rendered in HTML environment.
41
+ def alt_text
42
+ node = source_node.at('AltText')
43
+ node.nil? ? nil : node.content
44
+ end
45
+
46
+ # Type of companion resource, returned as a symbol. Either :static, :iframe, or :html.
47
+ def resource_type
48
+ if source_node.at('StaticResource')
49
+ :static
50
+ elsif source_node.at('IFrameResource')
51
+ :iframe
52
+ elsif source_node.at('HTMLResource')
53
+ :html
54
+ end
55
+ end
56
+
57
+ # Returns MIME type of static creative
58
+ def creative_type
59
+ if resource_type == :static
60
+ source_node.at('StaticResource')[:creativeType]
61
+ end
62
+ end
63
+
64
+ # Returns URI for static or iframe resource
65
+ def resource_url
66
+ case resource_type
67
+ when :static
68
+ URI.parse URI.escape(source_node.at('StaticResource').content.strip)
69
+ when :iframe
70
+ URI.parse URI.escape(source_node.at('IFrameResource').content.strip)
71
+ end
72
+ end
73
+
74
+ # Returns HTML text for html resource
75
+ def resource_html
76
+ if resource_type == :html
77
+ source_node.at('HTMLResource').content
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,62 @@
1
+ module VAST
2
+ # Contains the information related to a piece of creative.
3
+ #
4
+ # === Sequence
5
+ # The Creative element takes an optional “sequence” attribute that indicates the suggested order in which the
6
+ # Creatives should be displayed. If two Creative elements are intended to be shown at the same time they should
7
+ # share the same sequence number.
8
+ class Creative < Element
9
+
10
+ def ad
11
+ Ad.create source_node.ancestors('Ad').first
12
+ end
13
+
14
+ def id
15
+ creative_node[:id]
16
+ end
17
+
18
+ def ad_id
19
+ creative_node[:AdID]
20
+ end
21
+
22
+ # The preferred order in which multiple Creatives should be displayed
23
+ def sequence
24
+ creative_node[:sequence]
25
+ end
26
+
27
+ # Data to be passed into the video ad.
28
+ def ad_parameters
29
+ source_node.at('AdParameters').content
30
+ end
31
+
32
+ # Returns a hash, keyed by event name, containing an array of URIs to be called for each event.
33
+ def tracking_urls
34
+ tracking_urls = {}
35
+ source_node.xpath('.//Tracking').to_a.collect do |node|
36
+ underscored_name = underscore(node[:event])
37
+ if tracking_urls[underscored_name.to_sym]
38
+ tracking_urls[underscored_name.to_sym] << URI.parse(URI.escape(node.content.strip))
39
+ else
40
+ tracking_urls[underscored_name.to_sym] = [URI.parse(URI.escape(node.content.strip))]
41
+ end
42
+ end
43
+ tracking_urls
44
+ end
45
+
46
+ protected
47
+
48
+ def underscore(camel_cased_word)
49
+ camel_cased_word.to_s.gsub(/::/, '/').
50
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
51
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
52
+ tr("-", "_").
53
+ downcase
54
+ end
55
+
56
+ private
57
+
58
+ def creative_node
59
+ source_node.ancestors('Creative').first
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,71 @@
1
+ module VAST
2
+ # A complete VAST document
3
+ class Document < Nokogiri::XML::Document
4
+ @macros = ["ERRORCODE", "CONTENTPLAYHEAD", "CACHEBUSTING", "ASSETURI"]
5
+
6
+ def self.eval_macro(xml_string)
7
+ end
8
+
9
+ # Parse a VAST XML document
10
+ def self.parse(*args)
11
+ # VAST 3 support macro, need to uri escape all macros
12
+ if (args[0].is_a? String)
13
+ @macros.each{|x| args[0].gsub!("[#{x}]", "%5B#{x}%5D")}
14
+ end
15
+ super(*args)
16
+ end
17
+
18
+ # Same as parse, but raises InvalidDocumentError if document is not valid
19
+ def self.parse!(*args)
20
+ document = parse(*args)
21
+ raise InvalidDocumentError unless document.valid?
22
+ document
23
+ end
24
+
25
+ # Checks whether document conforms to the VAST XML Schema Definitions, accessible at
26
+ # http://www.iab.net/iab_products_and_industry_services/508676/digitalvideo/vast
27
+ def valid?
28
+ version_node = self.xpath('/VAST/@version').first
29
+ major_version = version_node ? version_node.value.to_i : 0
30
+ case major_version
31
+ when 2
32
+ xsd_file = VAST_SCHEMA_XSD_FILE
33
+ when 3
34
+ xsd_file = VAST3_SCHEMA_XSD_FILE
35
+ else
36
+ return false
37
+ end
38
+ xsd = Nokogiri::XML::Schema(File.read(xsd_file))
39
+ xsd.valid?(self)
40
+ end
41
+
42
+ # A single VAST response may include multiple Ads from multiple advertisers. It will be up to the
43
+ # Video Player to determine the order, timing, placement, etc for the multiple ads. However, the
44
+ # player should generally respect the sequential order of the Ad elements within the ad.
45
+ #
46
+ # If no ads of any type are available, it would be indicated by the absence of any ads.
47
+ def ads
48
+ self.root.xpath('.//Ad').to_a.collect do |node|
49
+ Ad.create(node)
50
+ end
51
+ end
52
+
53
+ # All inline ads
54
+ def inline_ads
55
+ ads.select{ |ad| ad.kind_of?(VAST::InlineAd) }
56
+ end
57
+
58
+ def ad_pod_ads
59
+ ads.select{ |ad| ad.sequence.is_a? Numeric }.sort{|x, y| x.sequence <=> y.sequence }
60
+ end
61
+
62
+ def stand_alone_ads
63
+ ads.select{ |ad| !ad.sequence.is_a?(Numeric) }
64
+ end
65
+
66
+ # All wrapper ads
67
+ def wrapper_ads
68
+ ads.select{ |ad| ad.kind_of?(VAST::WrapperAd) }
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,9 @@
1
+ module VAST
2
+ class Element
3
+ attr_reader :source_node
4
+
5
+ def initialize(node)
6
+ @source_node = node
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,18 @@
1
+ module VAST
2
+ # The VAST allows any valid XML within the extensions element. Use of extensions will necessarily
3
+ # require offline coordination between VAST sender and VAST receiver.
4
+ class Extension < Element
5
+
6
+ # Extension type
7
+ def type
8
+ source_node[:type]
9
+ end
10
+
11
+ # Access to the XML contents of this extension, as a Nokogiri::XML::Node
12
+ # http://nokogiri.rubyforge.org/nokogiri/Nokogiri/XML/Node.html. Alias of
13
+ # Extension#source_node
14
+ def xml
15
+ source_node
16
+ end
17
+ end
18
+ end
data/lib/vast/icon.rb ADDED
@@ -0,0 +1,87 @@
1
+ module VAST
2
+ # Any number of Mediafile objects can be provided for a single Ad, but it is assumed that all Mediafiles belongs
3
+ # to a single Ad object represent the same creative unit with the same duration, Ad-ID (ISCI code), etc.
4
+ class Icon < Element
5
+
6
+ def program
7
+ source_node[:program]
8
+ end
9
+
10
+ def width
11
+ source_node[:width].to_i
12
+ end
13
+
14
+ def height
15
+ source_node[:height].to_i
16
+ end
17
+
18
+ def xPosition
19
+ source_node[:xPosition].to_i
20
+ end
21
+
22
+ def yPosition
23
+ source_node[:yPosition].to_i
24
+ end
25
+
26
+ def duration
27
+ source_node[:duration].to_i
28
+ end
29
+
30
+ def offset
31
+ source_node[:offset].to_i
32
+ end
33
+
34
+ # Defines the method to use for communication with the companion
35
+ def api_framework
36
+ source_node[:apiFramework]
37
+ end
38
+
39
+ def resource_type
40
+ if source_node.at('StaticResource')
41
+ :static
42
+ elsif source_node.at('IFrameResource')
43
+ :iframe
44
+ elsif source_node.at('HTMLResource')
45
+ :html
46
+ end
47
+ end
48
+
49
+ # Returns MIME type of static creative
50
+ def creative_type
51
+ if resource_type == :static
52
+ source_node.at('StaticResource')[:creativeType]
53
+ end
54
+ end
55
+
56
+ # Returns URI for static or iframe resource
57
+ def resource_url
58
+ case resource_type
59
+ when :static
60
+ URI.parse URI.escape(source_node.at('StaticResource').content.strip)
61
+ when :iframe
62
+ URI.parse URI.escape(source_node.at('IFrameResource').content.strip)
63
+ end
64
+ end
65
+
66
+ # Returns HTML text for html resource
67
+ def resource_html
68
+ if resource_type == :html
69
+ source_node.at('HTMLResource').content
70
+ end
71
+ end
72
+
73
+ def click_through_url
74
+ URI.parse URI.escape(source_node.at('IconClickThrough').content.strip)
75
+ end
76
+
77
+ def click_tracking_url
78
+ URI.parse URI.escape(source_node.at('IconClickTracking').content.strip)
79
+ end
80
+
81
+ def view_tracking_url
82
+ URI.parse URI.escape(source_node.at('IconViewTracking').content.strip)
83
+ end
84
+
85
+ # end of class
86
+ end
87
+ end
@@ -0,0 +1,22 @@
1
+ module VAST
2
+ # Contains all the information necessary to display the visual experience of one complete ad.
3
+ class InlineAd < Ad
4
+
5
+ # URI of request to survey vendor
6
+ def survey_url
7
+ URI.parse URI.escape(source_node.at('Survey').content.strip)
8
+ end
9
+
10
+ # Common name of ad
11
+ def ad_system
12
+ source_node.at('AdSystem').content
13
+ end
14
+
15
+ # Common name of ad
16
+ def ad_title
17
+ source_node.at('AdTitle').content
18
+ end
19
+
20
+ end
21
+ end
22
+
@@ -0,0 +1,57 @@
1
+ module VAST
2
+ # LinearCreative is presented before, in the middle of, or after the video content is consumed by the user,
3
+ # in very much the same way a TV commercial can play before, during or after the chosen program.
4
+ class LinearCreative < Creative
5
+
6
+ # Duration of creative
7
+ def duration
8
+ source_node.at('Duration').content
9
+ end
10
+
11
+ # VAST 3
12
+ def skipoffset
13
+ source_node[:skipoffset]
14
+ end
15
+
16
+ # URI to open as destination page when user clicks on the video
17
+ def click_through_url
18
+ URI.parse URI.escape(source_node.at('ClickThrough').content.strip)
19
+ end
20
+
21
+ # An array of URIs to request for tracking purposes when user clicks on the video
22
+ def click_tracking_urls
23
+ source_node.xpath('.//ClickTracking').to_a.collect do |node|
24
+ URI.parse URI.escape(node.content.strip)
25
+ end
26
+ end
27
+
28
+ # A hash of URIs to request on custom events such as hotspotted video. This library
29
+ # required custom click urls to identify themselves with an `id` attribute, which is
30
+ # used as the key for this hash
31
+ def custom_click_urls
32
+ custom_click_urls = {}
33
+ source_node.xpath('.//CustomClick').to_a.collect do |node|
34
+ key = underscore(node[:id]).to_sym
35
+ custom_click_urls[key] = URI.parse(URI.escape(node.content.strip))
36
+ end
37
+ custom_click_urls
38
+ end
39
+
40
+ # Returns mediafiles containing the information required to display the linear creative's media
41
+ #
42
+ # It is assumed that all mediafiles accessible represent the same creative unit with the same
43
+ # duration, Ad-ID (ISCI code), etc.
44
+ def mediafiles
45
+ source_node.xpath('.//MediaFile').to_a.collect do |node|
46
+ Mediafile.new(node)
47
+ end
48
+ end
49
+
50
+ def icons
51
+ source_node.xpath('.//Icon').to_a.collect do |node|
52
+ Icon.new(node)
53
+ end
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,56 @@
1
+ module VAST
2
+ # Any number of Mediafile objects can be provided for a single Ad, but it is assumed that all Mediafiles belongs
3
+ # to a single Ad object represent the same creative unit with the same duration, Ad-ID (ISCI code), etc.
4
+ class Mediafile < Element
5
+
6
+ # Location of linear file
7
+ def url
8
+ URI.parse URI.escape(source_node.content.strip)
9
+ end
10
+
11
+ def id
12
+ source_node[:id]
13
+ end
14
+
15
+ # Method of delivery of ad, either "streaming" or "progressive"
16
+ def delivery
17
+ source_node[:delivery]
18
+ end
19
+
20
+ # MIME type. Popular MIME types include, but are not limited to “video/x-ms-wmv” for
21
+ # Windows Media, and “video/x-flv” for Flash Video.
22
+ def type
23
+ source_node[:type]
24
+ end
25
+
26
+ # Bitrate of encoded video in Kbps
27
+ def bitrate
28
+ source_node[:bitrate].to_i
29
+ end
30
+
31
+ # Pixel dimensions of video width
32
+ def width
33
+ source_node[:width].to_i
34
+ end
35
+
36
+ # Pixel dimensions of video height
37
+ def height
38
+ source_node[:height].to_i
39
+ end
40
+
41
+ # Defines the method to use for communication with the companion
42
+ def api_framework
43
+ source_node[:apiFramework]
44
+ end
45
+
46
+ # Whether it is acceptable to scale the mediafile.
47
+ def scalable?
48
+ source_node[:scalable]=="true"
49
+ end
50
+
51
+ # Whether the mediafile must have its aspect ratio maintained when scaled
52
+ def maintain_aspect_ratio?
53
+ source_node[:maintainAspectRatio]=="true"
54
+ end
55
+ end
56
+ end