stormpath-sdk 1.6.0 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (147) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +21 -0
  3. data/CHANGES.md +11 -0
  4. data/README.md +23 -25
  5. data/lib/stormpath-sdk.rb +11 -2
  6. data/lib/stormpath-sdk/api_key.rb +0 -1
  7. data/lib/stormpath-sdk/auth/basic_authenticator.rb +7 -7
  8. data/lib/stormpath-sdk/auth/basic_login_attempt.rb +7 -11
  9. data/lib/stormpath-sdk/auth/create_factor.rb +1 -1
  10. data/lib/stormpath-sdk/auth/register_service_provider.rb +41 -0
  11. data/lib/stormpath-sdk/auth/username_password_request.rb +3 -5
  12. data/lib/stormpath-sdk/cache/cache.rb +3 -3
  13. data/lib/stormpath-sdk/cache/cache_entry.rb +2 -2
  14. data/lib/stormpath-sdk/cache/cache_manager.rb +3 -4
  15. data/lib/stormpath-sdk/cache/cache_stats.rb +1 -3
  16. data/lib/stormpath-sdk/cache/disabled_cache_store.rb +5 -8
  17. data/lib/stormpath-sdk/cache/memory_store.rb +1 -1
  18. data/lib/stormpath-sdk/cache/redis_store.rb +4 -4
  19. data/lib/stormpath-sdk/client.rb +35 -33
  20. data/lib/stormpath-sdk/data_store.rb +278 -257
  21. data/lib/stormpath-sdk/error.rb +18 -7
  22. data/lib/stormpath-sdk/http/authc/sauthc1_signer.rb +76 -82
  23. data/lib/stormpath-sdk/http/http_client_request_executor.rb +10 -8
  24. data/lib/stormpath-sdk/http/response.rb +5 -7
  25. data/lib/stormpath-sdk/id_site/id_site_result.rb +5 -6
  26. data/lib/stormpath-sdk/oauth/access_token_authentication_result.rb +5 -9
  27. data/lib/stormpath-sdk/oauth/authenticator.rb +2 -2
  28. data/lib/stormpath-sdk/oauth/error.rb +4 -4
  29. data/lib/stormpath-sdk/oauth/id_site_grant_request.rb +1 -1
  30. data/lib/stormpath-sdk/oauth/password_grant_request.rb +1 -1
  31. data/lib/stormpath-sdk/oauth/refresh_grant_request.rb +2 -2
  32. data/lib/stormpath-sdk/oauth/stormpath_grant_request.rb +2 -2
  33. data/lib/stormpath-sdk/provider/account_access.rb +0 -2
  34. data/lib/stormpath-sdk/provider/account_result.rb +1 -2
  35. data/lib/stormpath-sdk/provider/facebook/facebook_provider.rb +6 -2
  36. data/lib/stormpath-sdk/provider/facebook/facebook_provider_data.rb +7 -3
  37. data/lib/stormpath-sdk/provider/github/github_provider.rb +6 -2
  38. data/lib/stormpath-sdk/provider/github/github_provider_data.rb +6 -2
  39. data/lib/stormpath-sdk/provider/google/google_provider.rb +7 -3
  40. data/lib/stormpath-sdk/provider/google/google_provider_data.rb +6 -2
  41. data/lib/stormpath-sdk/provider/linkedin/linkedin_provider.rb +6 -2
  42. data/lib/stormpath-sdk/provider/linkedin/linkedin_provider_data.rb +6 -2
  43. data/lib/stormpath-sdk/provider/provider.rb +8 -4
  44. data/lib/stormpath-sdk/provider/provider_data.rb +6 -2
  45. data/lib/stormpath-sdk/provider/saml/saml_provider.rb +10 -4
  46. data/lib/stormpath-sdk/provider/saml/saml_provider_data.rb +6 -3
  47. data/lib/stormpath-sdk/provider/stormpath/stormpath_provider.rb +6 -2
  48. data/lib/stormpath-sdk/provider/stormpath/stormpath_provider_data.rb +6 -2
  49. data/lib/stormpath-sdk/provider/twitter/twitter_provider.rb +6 -2
  50. data/lib/stormpath-sdk/provider/twitter/twitter_provider_data.rb +6 -2
  51. data/lib/stormpath-sdk/resource/account.rb +46 -40
  52. data/lib/stormpath-sdk/resource/account_link.rb +9 -5
  53. data/lib/stormpath-sdk/resource/account_linking_policy.rb +8 -4
  54. data/lib/stormpath-sdk/resource/account_membership.rb +1 -1
  55. data/lib/stormpath-sdk/resource/account_overrides.rb +20 -16
  56. data/lib/stormpath-sdk/resource/account_store.rb +15 -11
  57. data/lib/stormpath-sdk/resource/account_store_mapping.rb +14 -13
  58. data/lib/stormpath-sdk/resource/application.rb +147 -136
  59. data/lib/stormpath-sdk/resource/application_web_config.rb +11 -7
  60. data/lib/stormpath-sdk/resource/associations.rb +36 -43
  61. data/lib/stormpath-sdk/resource/attribute_statement_mapping_rules.rb +8 -0
  62. data/lib/stormpath-sdk/resource/base.rb +201 -200
  63. data/lib/stormpath-sdk/resource/challenge.rb +12 -8
  64. data/lib/stormpath-sdk/resource/collection.rb +77 -76
  65. data/lib/stormpath-sdk/resource/custom_data.rb +60 -61
  66. data/lib/stormpath-sdk/resource/custom_data_hash_methods.rb +28 -25
  67. data/lib/stormpath-sdk/resource/custom_data_storage.rb +18 -16
  68. data/lib/stormpath-sdk/resource/directory.rb +37 -60
  69. data/lib/stormpath-sdk/resource/email_verification_token.rb +7 -3
  70. data/lib/stormpath-sdk/resource/error.rb +8 -4
  71. data/lib/stormpath-sdk/resource/expansion.rb +22 -20
  72. data/lib/stormpath-sdk/resource/factor.rb +12 -8
  73. data/lib/stormpath-sdk/resource/field.rb +8 -4
  74. data/lib/stormpath-sdk/resource/group.rb +21 -16
  75. data/lib/stormpath-sdk/resource/group_membership.rb +7 -5
  76. data/lib/stormpath-sdk/resource/instance.rb +10 -6
  77. data/lib/stormpath-sdk/resource/linked_account.rb +7 -3
  78. data/lib/stormpath-sdk/resource/oauth_policy.rb +7 -3
  79. data/lib/stormpath-sdk/resource/organization.rb +14 -10
  80. data/lib/stormpath-sdk/resource/organization_account_store_mapping.rb +8 -4
  81. data/lib/stormpath-sdk/resource/password_reset_token.rb +9 -5
  82. data/lib/stormpath-sdk/resource/phone.rb +8 -4
  83. data/lib/stormpath-sdk/resource/registered_saml_service_provider.rb +8 -0
  84. data/lib/stormpath-sdk/resource/saml_identity_provider.rb +14 -0
  85. data/lib/stormpath-sdk/resource/saml_identity_provider_metadata.rb +9 -0
  86. data/lib/stormpath-sdk/resource/saml_policy.rb +10 -0
  87. data/lib/stormpath-sdk/resource/saml_service_provider.rb +7 -0
  88. data/lib/stormpath-sdk/{provider/saml/saml_mapping_rules.rb → resource/saml_service_provider_metadata.rb} +6 -5
  89. data/lib/stormpath-sdk/resource/saml_service_provider_registration.rb +11 -0
  90. data/lib/stormpath-sdk/resource/schema.rb +8 -4
  91. data/lib/stormpath-sdk/resource/tenant.rb +11 -8
  92. data/lib/stormpath-sdk/resource/user_info_mapping_rules.rb +7 -3
  93. data/lib/stormpath-sdk/resource/utils.rb +7 -10
  94. data/lib/stormpath-sdk/resource/verification_email.rb +7 -3
  95. data/lib/stormpath-sdk/resource/x_509_certificate.rb +7 -0
  96. data/lib/stormpath-sdk/util/assert.rb +1 -3
  97. data/lib/stormpath-sdk/version.rb +2 -2
  98. data/spec/auth/basic_authenticator_spec.rb +28 -24
  99. data/spec/auth/register_service_provider_spec.rb +68 -0
  100. data/spec/auth/sauthc1_signer_spec.rb +8 -4
  101. data/spec/cache/cache_entry_spec.rb +28 -29
  102. data/spec/cache/cache_spec.rb +9 -9
  103. data/spec/cache/cache_stats_spec.rb +1 -1
  104. data/spec/client_spec.rb +63 -63
  105. data/spec/data_store_spec.rb +23 -14
  106. data/spec/oauth/access_token_authentication_result_spec.rb +8 -2
  107. data/spec/provider/account_resolver_spec.rb +6 -4
  108. data/spec/provider/provider_spec.rb +6 -6
  109. data/spec/resource/account_creation_policy_spec.rb +1 -1
  110. data/spec/resource/account_link_spec.rb +7 -15
  111. data/spec/resource/account_spec.rb +17 -17
  112. data/spec/resource/account_store_mapping_spec.rb +16 -22
  113. data/spec/resource/account_store_spec.rb +3 -3
  114. data/spec/resource/application_spec.rb +324 -330
  115. data/spec/resource/base_spec.rb +7 -31
  116. data/spec/resource/collection_spec.rb +63 -114
  117. data/spec/resource/custom_data_spec.rb +1 -1
  118. data/spec/resource/directory_spec.rb +91 -87
  119. data/spec/resource/expansion_spec.rb +10 -10
  120. data/spec/resource/factor_spec.rb +1 -1
  121. data/spec/resource/group_spec.rb +1 -1
  122. data/spec/resource/linked_account_spec.rb +7 -7
  123. data/spec/resource/organization_spec.rb +12 -11
  124. data/spec/resource/phone_spec.rb +1 -1
  125. data/spec/resource/registered_saml_service_provider_spec.rb +35 -0
  126. data/spec/resource/saml_identity_provider_metadata_spec.rb +27 -0
  127. data/spec/resource/saml_identity_provider_spec.rb +94 -0
  128. data/spec/resource/saml_policy_spec.rb +27 -0
  129. data/spec/resource/saml_service_provider_registration_spec.rb +58 -0
  130. data/spec/resource/saml_service_provider_spec.rb +19 -0
  131. data/spec/resource/status_spec.rb +4 -3
  132. data/spec/resource/tenant_spec.rb +4 -6
  133. data/spec/spec_helper.rb +1 -1
  134. data/spec/support/custom_data_save_period.rb +4 -0
  135. data/spec/support/custom_data_storage_behavior.rb +7 -8
  136. data/spec/support/mocked_provider_accounts.rb +101 -101
  137. data/spec/support/mocked_saml_responses.rb +130 -0
  138. data/spec/support/resource_factory.rb +4 -4
  139. data/spec/support/resource_helpers.rb +10 -4
  140. data/spec/support/resource_matchers.rb +4 -4
  141. data/spec/support/test_request_executor.rb +2 -2
  142. metadata +21 -8
  143. data/lib/stormpath-sdk/provider/saml/saml_provider_metadata.rb +0 -19
  144. data/spec/fixtures/response/create_saml_directory.json +0 -26
  145. data/spec/fixtures/response/create_saml_directory_mapping_rules.json +0 -12
  146. data/spec/fixtures/response/get_saml_directory_provider.json +0 -16
  147. data/spec/fixtures/response/get_saml_directory_provider_metadata.json +0 -12
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright 2012 Stormpath, Inc.
2
+ # Copyright 2016 Stormpath, Inc.
3
3
  #
4
4
  # Licensed under the Apache License, Version 2.0 (the "License");
5
5
  # you may not use this file except in compliance with the License.
@@ -13,14 +13,18 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
  #
16
- class Stormpath::Resource::Challenge < Stormpath::Resource::Instance
17
- prop_accessor :message
18
- prop_reader :status, :created_at, :modified_at
16
+ module Stormpath
17
+ module Resource
18
+ class Challenge < Stormpath::Resource::Instance
19
+ prop_accessor :message
20
+ prop_reader :status, :created_at, :modified_at
19
21
 
20
- belongs_to :factor
21
- belongs_to :account
22
+ belongs_to :factor
23
+ belongs_to :account
22
24
 
23
- def validate(code)
24
- data_store.execute_raw_request href, { code: code }, Stormpath::Resource::Challenge
25
+ def validate(code)
26
+ data_store.execute_raw_request(href, { code: code }, Stormpath::Resource::Challenge)
27
+ end
28
+ end
25
29
  end
26
30
  end
@@ -13,101 +13,102 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
  #
16
- class Stormpath::Resource::Collection
17
- include Enumerable
18
-
19
- attr_reader :href, :client, :item_class, :collection_href, :criteria
20
-
21
- def initialize(href, item_class, client, options={})
22
- @client = client
23
- @href = href
24
- @item_class = item_class
25
- @collection_href = options[:collection_href] || @href
26
- @criteria ||= {}
27
- end
28
-
29
- def data_store
30
- client.data_store
31
- end
16
+ module Stormpath
17
+ module Resource
18
+ class Collection
19
+ include Enumerable
20
+
21
+ attr_reader :href, :client, :item_class, :collection_href, :criteria
22
+
23
+ def initialize(href, item_class, client, options = {})
24
+ @client = client
25
+ @href = href
26
+ @item_class = item_class
27
+ @collection_href = options[:collection_href] || @href
28
+ @criteria ||= {}
29
+ end
32
30
 
33
- def search query
34
- query_hash = if query.is_a? String
35
- { q: query }
36
- elsif query.is_a? Hash
37
- query
38
- end
31
+ def data_store
32
+ client.data_store
33
+ end
39
34
 
40
- criteria.merge! query_hash
41
- self
42
- end
35
+ def search(query)
36
+ query_hash = if query.is_a? String
37
+ { q: query }
38
+ elsif query.is_a? Hash
39
+ query
40
+ end
43
41
 
44
- def offset offset
45
- criteria.merge! offset: offset
46
- self
47
- end
42
+ criteria.merge! query_hash
43
+ self
44
+ end
48
45
 
49
- def limit limit
50
- criteria.merge! limit: limit
51
- self
52
- end
46
+ def offset(offset)
47
+ criteria[:offset] = offset
48
+ self
49
+ end
53
50
 
54
- def order statement
55
- criteria.merge! order_by: statement
56
- self
57
- end
51
+ def limit(limit)
52
+ criteria[:limit] = limit
53
+ self
54
+ end
58
55
 
59
- def each(&block)
60
- PaginatedIterator.iterate(collection_href, client, item_class, @criteria, &block)
61
- end
56
+ def order(statement)
57
+ criteria[:order_by] = statement
58
+ self
59
+ end
62
60
 
63
- def current_page
64
- page = CollectionPage.new(collection_href, client, criteria)
65
- page.item_type = item_class
66
- page
67
- end
61
+ def each(&block)
62
+ PaginatedIterator.iterate(collection_href, client, item_class, @criteria, &block)
63
+ end
68
64
 
69
- private
65
+ def current_page
66
+ page = CollectionPage.new(collection_href, client, criteria)
67
+ page.item_type = item_class
68
+ page
69
+ end
70
70
 
71
- module PaginatedIterator
71
+ private
72
72
 
73
- def self.iterate(collection_href, client, item_class, criteria, &block)
74
- page = CollectionPage.new collection_href, client, criteria
75
- page.item_type = item_class
73
+ module PaginatedIterator
74
+ def self.iterate(collection_href, client, item_class, criteria, &block)
75
+ page = CollectionPage.new(collection_href, client, criteria)
76
+ page.item_type = item_class
76
77
 
77
- unless page.items.count.zero?
78
- page.items.each(&block)
79
- criteria[:offset] = page.offset + page.limit
80
- iterate(collection_href, client, item_class, criteria, &block)
78
+ unless page.items.count.zero?
79
+ page.items.each(&block)
80
+ criteria[:offset] = page.offset + page.limit
81
+ iterate(collection_href, client, item_class, criteria, &block)
82
+ end
81
83
  end
82
84
  end
83
- end
84
85
 
85
- class CollectionPage < Stormpath::Resource::Base
86
- ITEMS = 'items'
86
+ class CollectionPage < Stormpath::Resource::Base
87
+ ITEMS = 'items'.freeze
87
88
 
88
- prop_accessor :offset, :limit, :size
89
+ prop_accessor :offset, :limit, :size
89
90
 
90
- attr_accessor :item_type
91
+ attr_accessor :item_type
91
92
 
92
- def items
93
- to_resource_array get_property(ITEMS)
94
- end
93
+ def items
94
+ to_resource_array(get_property(ITEMS))
95
+ end
95
96
 
96
- def to_resource properties
97
- data_store.instantiate item_type, properties
98
- end
97
+ def to_resource(properties)
98
+ data_store.instantiate(item_type, properties)
99
+ end
99
100
 
100
- def to_resource_array vals
101
- Array.new.tap do |items|
102
- if vals.is_a? Array
103
- vals.each do |val|
104
- resource = to_resource val
105
- items << resource
101
+ def to_resource_array(vals)
102
+ [].tap do |items|
103
+ if vals.is_a? Array
104
+ vals.each do |val|
105
+ resource = to_resource val
106
+ items << resource
107
+ end
106
108
  end
107
109
  end
108
110
  end
109
- end
110
-
111
- end#class Stormpath::Resource::Collection::CollectionPage
112
-
113
- end#Stormpath::Resource::Collection
111
+ end # class Stormpath::Resource::Collection::CollectionPage
112
+ end # Stormpath::Resource::Collection
113
+ end
114
+ end
@@ -13,82 +13,81 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
  #
16
- class Stormpath::Resource::CustomData < Stormpath::Resource::Instance
17
- include Stormpath::Resource::CustomDataHashMethods
16
+ module Stormpath
17
+ module Resource
18
+ class CustomData < Stormpath::Resource::Instance
19
+ include Stormpath::Resource::CustomDataHashMethods
18
20
 
19
- prop_reader :created_at, :modified_at
21
+ prop_reader :created_at, :modified_at
20
22
 
21
- def [](property_name)
22
- get_property property_name, ignore_camelcasing: true
23
- end
23
+ def [](property_name)
24
+ get_property property_name, ignore_camelcasing: true
25
+ end
24
26
 
25
- def []=(property_name, property_value)
26
- set_property property_name, property_value, ignore_camelcasing: true
27
- end
27
+ def []=(property_name, property_value)
28
+ set_property property_name, property_value, ignore_camelcasing: true
29
+ end
28
30
 
29
- def save
30
- if has_removed_properties?
31
- delete_removed_properties
32
- end
33
- if has_new_properties?
34
- super
35
- end
36
- end
31
+ def save
32
+ delete_removed_properties if has_removed_properties?
33
+ super if has_new_properties?
34
+ end
37
35
 
38
- def delete(name = nil)
39
- if name.nil?
40
- @properties = { HREF_PROP_NAME => @properties[HREF_PROP_NAME] }
41
- @dirty_properties.clear
42
- @deleted_properties.clear
43
- return super()
44
- end
36
+ def delete(name = nil)
37
+ if name.nil?
38
+ @properties = { HREF_PROP_NAME => @properties[HREF_PROP_NAME] }
39
+ @dirty_properties.clear
40
+ @deleted_properties.clear
41
+ return super()
42
+ end
45
43
 
46
- @write_lock.lock
47
- property_name = name.to_s
48
- begin
49
- @properties.delete(property_name)
50
- @dirty_properties.delete(property_name)
51
- @deleted_properties << property_name
52
- @dirty = true
53
- ensure
54
- @write_lock.unlock
55
- end
56
- end
44
+ @write_lock.lock
45
+ property_name = name.to_s
46
+ begin
47
+ @properties.delete(property_name)
48
+ @dirty_properties.delete(property_name)
49
+ @deleted_properties << property_name
50
+ @dirty = true
51
+ ensure
52
+ @write_lock.unlock
53
+ end
54
+ end
57
55
 
58
- private
56
+ private
59
57
 
60
- def sanitize(properties)
61
- {}.tap do |sanitized_properties|
62
- properties.map do |key, value|
63
- property_name = key.to_s
64
- sanitized_properties[property_name] = value
58
+ def sanitize(properties)
59
+ {}.tap do |sanitized_properties|
60
+ properties.map do |key, value|
61
+ property_name = key.to_s
62
+ sanitized_properties[property_name] = value
63
+ end
65
64
  end
66
65
  end
67
- end
68
66
 
69
- def has_removed_properties?
70
- @read_lock.lock
71
- begin
72
- !@deleted_properties.empty?
73
- ensure
74
- @read_lock.unlock
67
+ def has_removed_properties?
68
+ @read_lock.lock
69
+ begin
70
+ !@deleted_properties.empty?
71
+ ensure
72
+ @read_lock.unlock
73
+ end
75
74
  end
76
- end
77
75
 
78
- def has_new_properties?
79
- @read_lock.lock
80
- begin
81
- !@dirty_properties.empty?
82
- ensure
83
- @read_lock.unlock
76
+ def has_new_properties?
77
+ @read_lock.lock
78
+ begin
79
+ !@dirty_properties.empty?
80
+ ensure
81
+ @read_lock.unlock
82
+ end
84
83
  end
85
- end
86
84
 
87
- def delete_removed_properties
88
- @deleted_properties.delete_if do |deleted_property_name|
89
- data_store.delete self, deleted_property_name
90
- true
85
+ def delete_removed_properties
86
+ @deleted_properties.delete_if do |deleted_property_name|
87
+ data_store.delete(self, deleted_property_name)
88
+ true
89
+ end
91
90
  end
92
91
  end
93
-
92
+ end
94
93
  end
@@ -1,33 +1,36 @@
1
- module Stormpath::Resource::CustomDataHashMethods
2
- extend ActiveSupport::Concern
1
+ module Stormpath
2
+ module Resource
3
+ module CustomDataHashMethods
4
+ extend ActiveSupport::Concern
3
5
 
4
- included do
5
- def has_key?(key)
6
- materialize unless materialized?
7
- properties.has_key? key.to_s
8
- end
6
+ included do
7
+ def has_key?(key)
8
+ materialize unless materialized?
9
+ properties.key? key.to_s
10
+ end
9
11
 
10
- alias_method :include?, :has_key?
12
+ alias_method :include?, :has_key?
11
13
 
12
- def has_value?(value)
13
- materialize unless materialized?
14
- properties.has_value? value
15
- end
14
+ def has_value?(value)
15
+ materialize unless materialized?
16
+ properties.value? value
17
+ end
16
18
 
17
- def store(key, value)
18
- materialize unless materialized?
19
- self[key] = value
20
- end
19
+ def store(key, value)
20
+ materialize unless materialized?
21
+ self[key] = value
22
+ end
21
23
 
22
- def keys
23
- materialize unless materialized?
24
- properties.keys
25
- end
24
+ def keys
25
+ materialize unless materialized?
26
+ properties.keys
27
+ end
26
28
 
27
- def values
28
- materialize unless materialized?
29
- properties.values
29
+ def values
30
+ materialize unless materialized?
31
+ properties.values
32
+ end
33
+ end
30
34
  end
31
35
  end
32
-
33
- end
36
+ end
@@ -13,27 +13,29 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
  #
16
- module Stormpath::Resource::CustomDataStorage
17
- extend ActiveSupport::Concern
16
+ module Stormpath
17
+ module Resource
18
+ module CustomDataStorage
19
+ extend ActiveSupport::Concern
18
20
 
19
- CUSTOM_DATA = "custom_data"
21
+ CUSTOM_DATA = 'custom_data'.freeze
20
22
 
21
- included do
23
+ included do
24
+ def save
25
+ apply_custom_data_updates_if_necessary
26
+ super
27
+ end
22
28
 
23
- def save
24
- apply_custom_data_updates_if_necessary
25
- super
26
- end
29
+ def apply_custom_data_updates_if_necessary
30
+ if custom_data.send(:has_removed_properties?)
31
+ custom_data.send(:delete_removed_properties)
32
+ end
27
33
 
28
- def apply_custom_data_updates_if_necessary
29
- if custom_data.send :has_removed_properties?
30
- custom_data.send :delete_removed_properties
31
- end
32
- if custom_data.send :has_new_properties?
33
- self.set_property CUSTOM_DATA, custom_data.dirty_properties
34
+ if custom_data.send(:has_new_properties?)
35
+ set_property(CUSTOM_DATA, custom_data.dirty_properties)
36
+ end
37
+ end
34
38
  end
35
39
  end
36
-
37
40
  end
38
-
39
41
  end