parse_resource 1.5.9 → 1.5.11

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.
data/README.md CHANGED
@@ -69,53 +69,56 @@ end
69
69
  Creating, updating, and deleting:
70
70
 
71
71
  ```ruby
72
- > p = Post.new
72
+ p = Post.new
73
73
  => #<Post:0xab74864 @attributes={}, @unsaved_attributes={}>
74
- > p.valid?
74
+ p.valid?
75
75
  => false
76
- > p.errors
76
+ p.errors
77
77
  => #<ActiveModel::Errors:0xab71998 @base=#<Post:0xab74864 @attributes={}, @unsaved_attributes={}, @validation_context=nil, @errors=#<ActiveModel::Errors:0xab71998 ...>>, @messages={:title=>["can't be blank"]}>
78
- > p.title = "Introducing ParseResource"
78
+ p.title = "Introducing ParseResource"
79
79
  => "Introducing ParseResource"
80
- > p.valid?
80
+ p.valid?
81
81
  => true
82
- > p.author = "Alan deLevie"
82
+ p.author = "Alan deLevie"
83
83
  => "Alan deLevie"
84
- > p.body = "Ipso Lorem"
84
+ p.body = "Ipso Lorem"
85
85
  => "Ipso Lorem"
86
- > p.save
86
+ p.save
87
87
  => #<Post:0xab74864 @attributes={:title=>"Introducing ParseResource", :author=>"Alan deLevie", :body=>"Ipso Lorem", :createdAt=>"2011-09-19T01:32:04.973Z", :objectId=>"QARfXUILgY"}, @unsaved_attributes={}, @validation_context=nil, @errors=#<ActiveModel::Errors:0xab71998 @base=#<Post:0xab74864 ...>, @messages={}>>
88
- > p.id
88
+ p.id
89
89
  => "QARfXUILgY"
90
- > p.updated_at
90
+ p.updated_at
91
91
  => nil
92
- > p.created_at
92
+ p.created_at
93
93
  => "2011-09-19T01:32:04.973Z"
94
- > p.title = "[Update] Introducing ParseResource"
94
+ p.title = "[Update] Introducing ParseResource"
95
95
  => "[Update] Introducing ParseResource"
96
- > p.save
96
+ p.save
97
97
  => #<Post:0xab74864 @attributes={:title=>"[Update] Introducing ParseResource", :author=>"Alan deLevie", :body=>"Ipso Lorem", :createdAt=>"2011-09-19T01:32:04.973Z", :objectId=>"QARfXUILgY", :updatedAt=>"2011-09-19T01:32:37.930Z", "title"=>"[Update] Introducing ParseResource"}, @unsaved_attributes={}, @validation_context=nil, @errors=#<ActiveModel::Errors:0xab71998 @base=#<Post:0xab74864 ...>, @messages={}>>
98
- > p.updated_at
98
+ p.updated_at
99
99
  => "2011-09-19T01:32:37.930Z"
100
- > p.destroy
100
+ p.destroy
101
101
  => nil
102
- > p.title
102
+ p.title
103
103
  => nil
104
104
  ```
105
105
 
106
106
  Finding:
107
107
 
108
108
  ```ruby
109
- > a = Post.create(:title => "foo", :author => "bar", :body => "ipso")
109
+ a = Post.create(:title => "foo", :author => "bar", :body => "ipso")
110
110
  => #<Post:0xa6eee34 @attributes={:title=>"foo", :author=>"bar", :body=>"ipso", :createdAt=>"2011-09-19T01:36:42.833Z", :objectId=>"dPjKwaqQUv"}, @unsaved_attributes={}, @validation_context=nil, @errors=#<ActiveModel::Errors:0xa6ee54c @base=#<Post:0xa6eee34 ...>, @messages={}>>
111
- > b = Post.create(:title => "a newer post", :author => "bar", :body => "some newer content")
111
+ b = Post.create(:title => "a newer post", :author => "bar", :body => "some newer content")
112
112
  => #<Post:0xa6b5e68 @attributes={:title=>"a newer post", :author=>"bar", :body=>"some newer content", :createdAt=>"2011-09-19T01:37:16.805Z", :objectId=>"ZripqKvunV"}, @unsaved_attributes={}, @validation_context=nil, @errors=#<ActiveModel::Errors:0xa6b5710 @base=#<Post:0xa6b5e68 ...>, @messages={}>>
113
- > posts = Post.where(:author => "bar")
113
+ posts = Post.where(:author => "bar")
114
114
  => [#<Post:0xa67b830 @attributes={:body=>"ipso", :author=>"bar", :title=>"foo", :updatedAt=>"2011-09-19T01:36:42.834Z", :createdAt=>"2011-09-19T01:36:42.834Z", :objectId=>"dPjKwaqQUv"}, @unsaved_attributes={:body=>"ipso", :author=>"bar", :title=>"foo", :updatedAt=>"2011-09-19T01:36:42.834Z", :createdAt=>"2011-09-19T01:36:42.834Z", :objectId=>"dPjKwaqQUv"}>, #<Post:0xa67b088 @attributes={:body=>"some newer content", :author=>"bar", :title=>"a newer post", :updatedAt=>"2011-09-19T01:37:16.805Z", :createdAt=>"2011-09-19T01:37:16.805Z", :objectId=>"ZripqKvunV"}, @unsaved_attributes={:body=>"some newer content", :author=>"bar", :title=>"a newer post", :updatedAt=>"2011-09-19T01:37:16.805Z", :createdAt=>"2011-09-19T01:37:16.805Z", :objectId=>"ZripqKvunV"}>]
115
- > p = Post.first
115
+ p = Post.first
116
116
  => #<Post:0xa640dd4 @attributes={:body=>"ipso", :author=>"bar", :title=>"foo", :updatedAt=>"2011-09-19T01:36:42.834Z", :createdAt=>"2011-09-19T01:36:42.834Z", :objectId=>"dPjKwaqQUv"}, @unsaved_attributes={:body=>"ipso", :author=>"bar", :title=>"foo", :updatedAt=>"2011-09-19T01:36:42.834Z", :createdAt=>"2011-09-19T01:36:42.834Z", :objectId=>"dPjKwaqQUv"}>
117
- > posts = Post.all
118
- => [#<Post:0xa6236a8 @attributes={:body=>"ipso", :author=>"bar", :title=>"foo", :updatedAt=>"2011-09-19T01:36:42.834Z", :createdAt=>"2011-09-19T01:36:42.834Z", :objectId=>"dPjKwaqQUv"}, @unsaved_attributes={:body=>"ipso", :author=>"bar", :title=>"foo", :updatedAt=>"2011-09-19T01:36:42.834Z", :createdAt=>"2011-09-19T01:36:42.834Z", :objectId=>"dPjKwaqQUv"}>, #<Post:0xa6226cc @attributes={:body=>"some newer content", :author=>"bar", :title=>"a newer post", :updatedAt=>"2011-09-19T01:37:16.805Z", :createdAt=>"2011-09-19T01:37:16.805Z", :objectId=>"ZripqKvunV"}, @unsaved_attributes={:body=>"some newer content", :author=>"bar", :title=>"a newer post", :updatedAt=>"2011-09-19T01:37:16.805Z", :createdAt=>"2011-09-19T01:37:16.805Z", :objectId=>"ZripqKvunV"}>]
117
+ posts = Post.all
118
+ => [#<Post:0xa6236a8 @attributes={:body=>"ipso", :author=>"bar", :title=>"foo", :updatedAt=>"2011-09-19T01:36:42.834Z", :createdAt=>"2011-09-19T01:36:42.834Z", :objectId=>"dPjKwaqQUv"}, @unsaved_attributes={:body=>"ipso", :author=>"bar", :title=>"foo", :updatedAt=>"2011-09-19T01:36:42.834Z", :createdAt=>"2011-09-19T01:36:42.834Z", :objectId=>"dPjKwaqQUv"}>, #<Post:0xa6226cc @attributes={:body=>"some newer content", :author=>"bar", :title=>"a newer post", :updatedAt=>"2011-09-19T01:37:16.805Z", :createdAt=>"2011-09-19T01:37:16.805Z", :objectId=>"ZripqKvunV"}, @unsaved_attributes={:body=>"some newer content", :author=>"bar", :title=>"a newer post", :updatedAt=>"2011-09-19T01:37:16.805Z", :createdAt=>"2011-09-19T01:37:16.805Z", :objectId=>"ZripqKvunV"}>]
119
+ id = "DjiH4Qffke"
120
+ p = Post.find(id)
121
+ => #<Post:0xa50f028 @unsaved_attributes={}, @attributes={"title"=>"fvvV", "updatedAt"=>"2011-09-22T21:36:13.044Z", "createdAt"=>"2011-09-22T21:36:13.044Z", "objectId"=>"DjiH4Qffke"}>
119
122
  ```
120
123
 
121
124
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.5.9
1
+ 1.5.11
@@ -1,7 +1,15 @@
1
1
  require 'parse_resource'
2
+ require 'pp'
3
+
4
+
5
+ ParseResource.load!("FKEzdzDgEyghLDFgIVHYJehVlWpfVtUmEv4MUEkJ", "bOYO7usWbrcIbL5L5bPzlYrSonQRvwJecC1XLsuN")
2
6
 
3
7
  class Post < ParseResource
4
- fields :title, :body, :author
8
+ fields :title, :author, :body
9
+
10
+ after_save :add_author
5
11
 
6
- validates_presence_of :title
12
+ def add_author
13
+ update(:author => "Alan")
14
+ end
7
15
  end
@@ -4,7 +4,9 @@ require "active_model"
4
4
  require "erb"
5
5
  require "rest-client"
6
6
  require "json"
7
- require "active_support"
7
+ require "active_support/hash_with_indifferent_access"
8
+
9
+ ActiveSupport
8
10
 
9
11
  class ParseResource
10
12
  # ParseResource provides an easy way to use Ruby to interace with a Parse.com backend
@@ -17,11 +19,16 @@ class ParseResource
17
19
  include ActiveModel::Conversion
18
20
  include ActiveModel::AttributeMethods
19
21
  extend ActiveModel::Naming
22
+ extend ActiveModel::Callbacks
23
+ HashWithIndifferentAccess = ActiveSupport::HashWithIndifferentAccess
24
+
25
+ #define_model_callbacks :initialize, :find, :only => :after
26
+ define_model_callbacks :save, :create, :update, :destroy
20
27
 
21
28
  # instantiation!
22
29
  # p = Post.new(:title => "cool story")
23
30
  def initialize(attributes = {}, new=true)
24
- attributes.each_key {}
31
+ attributes = HashWithIndifferentAccess.new(attributes)
25
32
  if new
26
33
  @unsaved_attributes = attributes
27
34
  else
@@ -67,12 +74,8 @@ class ParseResource
67
74
  if k.is_a?(Symbol)
68
75
  k = k.to_s
69
76
  end
70
-
71
- if @attributes[k.to_s]
72
- @attributes[k.to_s]
73
- else
74
- @unsaved_attributes[k.to_s]
75
- end
77
+
78
+ @attributes[k.to_s]
76
79
  end
77
80
  end
78
81
  end
@@ -120,6 +123,7 @@ class ParseResource
120
123
 
121
124
  # Post.create(:title => "new post")
122
125
  def create(attributes = {})
126
+ attributes = HashWithIndifferentAccess.new(attributes)
123
127
  new(attributes).save
124
128
  end
125
129
 
@@ -161,6 +165,7 @@ class ParseResource
161
165
  resp = self.resource.post(@unsaved_attributes.to_json, :content_type => "application/json")
162
166
  @attributes.merge!(JSON.parse(resp))
163
167
  @attributes.merge!(@unsaved_attributes)
168
+ attributes = HashWithIndifferentAccess.new(attributes)
164
169
  @unsaved_attributes = {}
165
170
  create_setters!
166
171
  self
@@ -168,7 +173,9 @@ class ParseResource
168
173
 
169
174
  def save
170
175
  if valid?
171
- new? ? create : update
176
+ run_callbacks :save do
177
+ new? ? create : update
178
+ end
172
179
  else
173
180
  false
174
181
  end
@@ -176,6 +183,7 @@ class ParseResource
176
183
  end
177
184
 
178
185
  def update(attributes = {})
186
+ attributes = HashWithIndifferentAccess.new(attributes)
179
187
  @unsaved_attributes.merge!(attributes)
180
188
 
181
189
  put_attrs = @unsaved_attributes
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "parse_resource"
8
- s.version = "1.5.9"
8
+ s.version = "1.5.11"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Alan deLevie"]
12
- s.date = "2011-09-30"
12
+ s.date = "2011-10-01"
13
13
  s.description = ""
14
14
  s.email = "adelevie@gmail.com"
15
15
  s.extra_rdoc_files = [
@@ -32,6 +32,7 @@ Gem::Specification.new do |s|
32
32
  "rdoc/index.html",
33
33
  "rdoc/lib/parse_resource_rb.html",
34
34
  "rdoc/rdoc.css",
35
+ "test/active_model_lint_test.rb",
35
36
  "test/helper.rb",
36
37
  "test/test_parse_resource.rb"
37
38
  ]
@@ -0,0 +1,19 @@
1
+ require 'helper'
2
+ require 'parse_resource'
3
+
4
+ path = "parse_resource.yml"
5
+ settings = YAML.load(ERB.new(File.new(path).read).result)['test']
6
+
7
+ ParseResource.load!(settings['app_id'], settings['master_key'])
8
+
9
+ class Post < ParseResource
10
+ fields :title, :body, :author
11
+ validates_presence_of :title
12
+ end
13
+ class ActiveModelLintTest < ActiveModel::TestCase
14
+ include ActiveModel::Lint::Tests
15
+
16
+ def setup
17
+ @model = Post.new
18
+ end
19
+ end
@@ -1,27 +1,118 @@
1
1
  require 'helper'
2
2
  require 'parse_resource'
3
3
 
4
+ path = "parse_resource.yml"
5
+ settings = YAML.load(ERB.new(File.new(path).read).result)['test']
6
+
7
+ ParseResource.load!(settings['app_id'], settings['master_key'])
8
+
4
9
  class Post < ParseResource
5
10
  fields :title, :body, :author
6
11
  validates_presence_of :title
7
12
  end
8
13
 
9
- class Tweet < ParseResource
10
- end
11
-
12
14
  class TestParseResource < Test::Unit::TestCase
13
15
 
14
16
  def test_initialize_without_args
15
17
  assert Post.new.is_a?(Post)
16
- assert Tweet.new.is_a?(Tweet)
17
18
  end
18
19
 
19
20
  def test_initialize_with_args
20
- p = Post.new(:title => "title1", :body => "ipso")
21
- t = Tweet.new(:user => "aplusk")
22
- assert_equal p.title, "title1"
23
- assert_equal p.body, "ipso"
24
- assert_equal t.user, "aplusk"
21
+ @post = Post.new(:title => "title1", :body => "ipso")
22
+ assert @post.is_a?(Post)
23
+ assert_equal @post.title, "title1"
24
+ assert_equal @post.body, "ipso"
25
+ end
26
+
27
+ def test_create
28
+ p = Post.create(:title => "1234567890created!")
29
+ assert p.is_a?(Post)
30
+ @find_id = p.id
31
+ assert p.id
32
+ assert p.created_at
33
+ end
34
+
35
+ def test_find
36
+ p1 = Post.create(:title => "Welcome")
37
+ p2 = Post.find(p1.id)
38
+ assert_equal p2.id, p2.id
39
+ end
40
+
41
+ def test_first
42
+ p = Post.first
43
+ assert p.is_a?(Post)
44
+ end
45
+
46
+ def test_where
47
+ p1 = Post.create(:title => "Welcome111")
48
+ p2 = Post.where(:title => "Welcome111").first
49
+ assert_equal p2.id, p1.id
50
+ end
51
+
52
+ def test_all
53
+ Post.create(:title => "11222")
54
+ Post.create(:title => "112ssd22")
55
+ posts = Post.all
56
+ assert posts.is_a?(Array)
57
+ assert posts[0].is_a?(Post)
58
+ end
59
+
60
+ def test_attribute_getters
61
+ @post = Post.create(:title => "title1")
62
+ assert_equal @post.attributes['title'], "title1"
63
+ assert_equal @post.attributes['title'], @post.title
64
+ end
65
+
66
+ def test_attribute_setters
67
+ @post = Post.create(:title => "1")
68
+ @post.body = "newerbody"
69
+ assert_equal @post.body, "newerbody"
70
+ end
71
+
72
+ def test_save
73
+ @post = Post.create(:title => "testing save")
74
+ assert @post.save
75
+ assert @post.attributes['objectId']
76
+ assert @post.attributes['updatedAt']
77
+ assert @post.attributes['createdAt']
78
+ end
79
+
80
+ def test_id
81
+ @post = Post.create(:title => "testing id")
82
+ assert @post.respond_to?(:id)
83
+ assert @post.id
84
+ assert @post.attributes['objectId'] = @post.id
85
+ end
86
+
87
+ def test_created_at
88
+ @post = Post.create(:title => "testing created_at")
89
+ assert @post.respond_to?(:created_at)
90
+ assert @post.created_at
91
+ assert @post.attributes['createdAt']
92
+ end
93
+
94
+ def test_updated_at
95
+ @post = Post.create(:title => "testing updated_at")
96
+ @post.title = "something else"
97
+ @post.save
98
+ assert @post.updated_at
99
+ end
100
+
101
+ def test_update
102
+ @post = Post.create(:title => "stale title")
103
+ updated_once = @post.updated_at
104
+ @post.update(:title => "updated title")
105
+ assert_equal @post.title, "updated title"
106
+ @post.title = "updated from setter"
107
+ assert_equal @post.title, "updated from setter"
108
+ assert_not_equal @post.updated_at, updated_once
109
+ end
110
+
111
+ def test_destroy
112
+ p = Post.create(:title => "hello1234567890abc!")
113
+ id = p.id
114
+ p.destroy
115
+ assert_equal 0, Post.where(:title => "hello1234567890abc!", :objectId => id).length
25
116
  end
26
117
 
27
118
  def test_validation
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: parse_resource
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.9
4
+ version: 1.5.11
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-09-30 00:00:00.000000000Z
12
+ date: 2011-10-01 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rest-client
16
- requirement: &80539030 !ruby/object:Gem::Requirement
16
+ requirement: &81619260 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *80539030
24
+ version_requirements: *81619260
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: activesupport
27
- requirement: &80538720 !ruby/object:Gem::Requirement
27
+ requirement: &81619010 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *80538720
35
+ version_requirements: *81619010
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: activemodel
38
- requirement: &80538320 !ruby/object:Gem::Requirement
38
+ requirement: &81618760 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *80538320
46
+ version_requirements: *81618760
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: bundler
49
- requirement: &80529150 !ruby/object:Gem::Requirement
49
+ requirement: &81618520 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 1.0.0
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *80529150
57
+ version_requirements: *81618520
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: jeweler
60
- requirement: &80528860 !ruby/object:Gem::Requirement
60
+ requirement: &81618280 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ~>
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: 1.6.4
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *80528860
68
+ version_requirements: *81618280
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rcov
71
- requirement: &80528510 !ruby/object:Gem::Requirement
71
+ requirement: &81618030 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *80528510
79
+ version_requirements: *81618030
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: reek
82
- requirement: &80528220 !ruby/object:Gem::Requirement
82
+ requirement: &81617710 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ~>
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: 1.2.8
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *80528220
90
+ version_requirements: *81617710
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: rest-client
93
- requirement: &80527910 !ruby/object:Gem::Requirement
93
+ requirement: &81617380 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ! '>='
@@ -98,10 +98,10 @@ dependencies:
98
98
  version: '0'
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *80527910
101
+ version_requirements: *81617380
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: activesupport
104
- requirement: &80527360 !ruby/object:Gem::Requirement
104
+ requirement: &81616980 !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
107
  - - ! '>='
@@ -109,10 +109,10 @@ dependencies:
109
109
  version: '0'
110
110
  type: :development
111
111
  prerelease: false
112
- version_requirements: *80527360
112
+ version_requirements: *81616980
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: activemodel
115
- requirement: &80527060 !ruby/object:Gem::Requirement
115
+ requirement: &81616420 !ruby/object:Gem::Requirement
116
116
  none: false
117
117
  requirements:
118
118
  - - ! '>='
@@ -120,7 +120,7 @@ dependencies:
120
120
  version: '0'
121
121
  type: :development
122
122
  prerelease: false
123
- version_requirements: *80527060
123
+ version_requirements: *81616420
124
124
  description: ''
125
125
  email: adelevie@gmail.com
126
126
  executables: []
@@ -144,6 +144,7 @@ files:
144
144
  - rdoc/index.html
145
145
  - rdoc/lib/parse_resource_rb.html
146
146
  - rdoc/rdoc.css
147
+ - test/active_model_lint_test.rb
147
148
  - test/helper.rb
148
149
  - test/test_parse_resource.rb
149
150
  homepage: http://github.com/adelevie/parse_resource
@@ -161,7 +162,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
161
162
  version: '0'
162
163
  segments:
163
164
  - 0
164
- hash: -761899121
165
+ hash: -627658479
165
166
  required_rubygems_version: !ruby/object:Gem::Requirement
166
167
  none: false
167
168
  requirements: