my_john_deere_api 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e2ae704f57aab2fa5c33972e626c85de1f4c870094f5b4e3807025da0bea6325
4
- data.tar.gz: 46a6f1d705a307c09829ae49b8df13cc8bdd49f7c5b650c8ea9d2d13b918ca6d
3
+ metadata.gz: 0a4a505a402a82195b10345e48301897a6af477a4ba60711c33caee9d77ba764
4
+ data.tar.gz: 4f3f21b7b110b76be7bcc99195b380a3d05154443cbab36732e1f32a0dc830b2
5
5
  SHA512:
6
- metadata.gz: abbd9e17e1ed5c709595de082e120381985aff0f78dfcd836474ad0f0de3fc1481a330484cec14962625bd658f5e89235f2ad5de40546fc247393898121e1e5a
7
- data.tar.gz: 4cf59f13b1cedf18648871e9e5cc623d0c43f939e0e1a440f006c2e32949bf67f6754090ecf38bfd6d9c4c1e29801f633e7b9e57cf458e6cf4cc5d55ade3a114
6
+ metadata.gz: 19b70538ef4d795113246f269c97f6efe22cd2ccb79903d5433ee8aad79fc5823eb383e047bac8409f37f73a01658519a2fa3ceb10740416945833db8e9f6388
7
+ data.tar.gz: f0bbf336465ab99361e74e5102abd2dc6ebb2b74116988e5c9b8319aa28a2bf104a02c5209d2759904624ddd340aa9db019f819d93d20a63f2a5d82ae1b6450d
data/Rakefile CHANGED
@@ -2,6 +2,7 @@ require 'rake/testtask'
2
2
 
3
3
  Rake::TestTask.new do |t|
4
4
  t.libs << 'test'
5
+ t.pattern = 'test/**/test*.rb'
5
6
  end
6
7
 
7
8
  desc "Run tests"
@@ -1,5 +1,8 @@
1
+ require 'oauth'
2
+ require 'uri'
1
3
  require 'json'
2
4
 
3
5
  module MyJohnDeereApi
4
6
  autoload :VERSION, 'my_john_deere_api/version'
7
+ autoload :Authorize, 'my_john_deere_api/authorize'
5
8
  end
@@ -0,0 +1,80 @@
1
+ class MyJohnDeereApi::Authorize
2
+ attr_reader :api_key, :api_secret, :request_token, :request_secret
3
+ attr_accessor :base_url
4
+
5
+ DEFAULTS = {
6
+ base_url: 'https://api.soa-proxy.deere.com',
7
+ }
8
+
9
+ def initialize(api_key, api_secret, options={})
10
+ @api_key = api_key
11
+ @api_secret = api_secret
12
+ @base_url = options[:base_url] || ENV['MY_JOHN_DEERE_URL'] || DEFAULTS[:base_url]
13
+ end
14
+
15
+ def authorize_url
16
+ return @authorize_url if defined?(@authorize_url)
17
+
18
+ requester = app_consumer.get_request_token
19
+
20
+ @request_token = requester.token
21
+ @request_secret = requester.secret
22
+
23
+ @authorize_url = requester.authorize_url
24
+ end
25
+
26
+ def app_consumer
27
+ @app_consumer ||= consumer(base_url)
28
+ end
29
+
30
+ def user_consumer
31
+ @user_consumer ||= consumer("#{base_url}/platform")
32
+ end
33
+
34
+ def consumer(site)
35
+ OAuth::Consumer.new(
36
+ api_key,
37
+ api_secret,
38
+ site: site,
39
+ header: header,
40
+ http_method: :get,
41
+ request_token_url: links[:request_token],
42
+ access_token_url: links[:access_token],
43
+ authorize_url: links[:authorize_request_token]
44
+ )
45
+ end
46
+
47
+ def links
48
+ return @links if defined?(@links)
49
+
50
+ catalog = OAuth::Consumer.new(api_key, api_secret)
51
+ .request(
52
+ :get,
53
+ "#{base_url}/platform/",
54
+ nil,
55
+ {},
56
+ header
57
+ ).body
58
+
59
+ @links = {}
60
+
61
+ JSON.parse(catalog)['links'].each do |link|
62
+ uri = URI.parse(link['uri'])
63
+ uri.query = nil
64
+
65
+ @links[keyify(link['rel'])] = uri.to_s
66
+ end
67
+
68
+ @links
69
+ end
70
+
71
+ private
72
+
73
+ def header
74
+ {accept: 'application/vnd.deere.axiom.v3+json'}
75
+ end
76
+
77
+ def keyify key_name
78
+ key_name.gsub(/^oauth/, '').gsub(/([a-z])([A-Z])/, '\1_\2').downcase.to_sym
79
+ end
80
+ end
@@ -1,3 +1,3 @@
1
1
  module MyJohnDeereApi
2
- VERSION = '0.0.1'
3
- end
2
+ VERSION='0.0.2'
3
+ end
@@ -0,0 +1,132 @@
1
+ require 'uri'
2
+ require 'cgi'
3
+ require 'support/helper'
4
+
5
+ URL_ENV = 'MY_JOHN_DEERE_URL'
6
+ TOKEN_PATTERN = /^[0-9a-z\-]+$/
7
+ SECRET_PATTERN = /^[0-9A-Za-z\-+=\/]+$/
8
+ API_KEY = ENV['API_KEY']
9
+ API_SECRET = ENV['API_SECRET']
10
+
11
+ def contains_parameters?(uri)
12
+ !URI.parse(uri).query.nil?
13
+ end
14
+
15
+ def create_authorize
16
+ JD::Authorize.new(API_KEY, API_SECRET, base_url: 'https://sandboxapi.deere.com')
17
+ end
18
+
19
+ def fancy_url
20
+ 'https://example.com/turtles'
21
+ end
22
+
23
+ class AuthorizeTest < MiniTest::Test
24
+ describe 'initialization' do
25
+ it "accepts an API key and secret" do
26
+ authorize = JD::Authorize.new('key', 'secret')
27
+
28
+ assert_equal 'key', authorize.api_key
29
+ assert_equal 'secret', authorize.api_secret
30
+ end
31
+
32
+ it "can set the base_url" do
33
+ authorize = JD::Authorize.new('key', 'secret', base_url: fancy_url)
34
+ assert_equal fancy_url, authorize.base_url
35
+ end
36
+
37
+ it 'prefers passed-in base_url over ENV variable' do
38
+ ENV[URL_ENV] = 'https://example.com/disposable'
39
+
40
+ authorize = JD::Authorize.new('key', 'secret', base_url: fancy_url)
41
+ assert_equal fancy_url, authorize.base_url
42
+
43
+ ENV.delete(URL_ENV)
44
+ end
45
+ end
46
+
47
+ describe '#authorize_url' do
48
+ it 'retrieves a request url' do
49
+ authorize = create_authorize
50
+
51
+ url = VCR.use_cassette('get_request_token') { authorize.authorize_url }
52
+
53
+ assert_includes url, "#{authorize.links[:authorize_request_token]}?oauth_token="
54
+
55
+ query = URI.parse(url).query
56
+ params = CGI::parse(query)
57
+
58
+ assert_match(TOKEN_PATTERN, params['oauth_token'].first)
59
+ end
60
+
61
+ it 'sets the request token/secret' do
62
+ authorize = create_authorize
63
+
64
+ VCR.use_cassette('get_request_token') { authorize.authorize_url }
65
+
66
+ assert_match TOKEN_PATTERN, authorize.request_token
67
+ assert_match SECRET_PATTERN, authorize.request_secret
68
+ end
69
+ end
70
+
71
+ describe '#links' do
72
+ it "returns a list of catalog urls" do
73
+ authorize = create_authorize
74
+
75
+ links = VCR.use_cassette("catalog"){ authorize.links }
76
+
77
+ assert_kind_of Hash, links
78
+
79
+ [:request_token, :authorize_request_token, :access_token].each do |link|
80
+ assert links.has_key?(link)
81
+ refute contains_parameters?(links[link])
82
+ end
83
+ end
84
+ end
85
+
86
+ describe '#base_url' do
87
+ it 'defaults to production deere url' do
88
+ authorize = JD::Authorize.new('key', 'secret')
89
+ assert_equal 'https://api.soa-proxy.deere.com', authorize.base_url
90
+ end
91
+
92
+ it 'can be set via accessor' do
93
+ authorize = create_authorize
94
+ authorize.base_url = fancy_url
95
+
96
+ assert_equal fancy_url, authorize.base_url
97
+ end
98
+
99
+ it 'can be set via environment variable' do
100
+ ENV[URL_ENV] = fancy_url
101
+
102
+ authorize = JD::Authorize.new('key', 'secret')
103
+ assert_equal fancy_url, authorize.base_url
104
+
105
+ ENV.delete(URL_ENV)
106
+ end
107
+ end
108
+
109
+ describe '#app_consumer' do
110
+ it 'creates a working oAuth consumer for non-user-specific requests' do
111
+ auth = create_authorize
112
+ app_consumer = VCR.use_cassette('app_consumer') { auth.app_consumer }
113
+
114
+ assert_kind_of OAuth::Consumer, app_consumer
115
+ assert_equal API_KEY, app_consumer.key
116
+ assert_equal API_SECRET, app_consumer.secret
117
+ assert_equal auth.base_url, app_consumer.site
118
+ end
119
+ end
120
+
121
+ describe '#user_consumer' do
122
+ it 'creates a working oAuth consumer for user-specific requests' do
123
+ auth = create_authorize
124
+ user_consumer = VCR.use_cassette('app_consumer') { auth.user_consumer }
125
+
126
+ assert_kind_of OAuth::Consumer, user_consumer
127
+ assert_equal API_KEY, user_consumer.key
128
+ assert_equal API_SECRET, user_consumer.secret
129
+ assert_equal "#{auth.base_url}/platform", user_consumer.site
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,9 @@
1
+ require 'support/helper'
2
+
3
+ class VersionTest < MiniTest::Test
4
+ describe 'VERSION' do
5
+ it 'conforms to the semantic version format' do
6
+ assert_match(/^\d+\.\d+\.\d+$/, MyJohnDeereApi::VERSION)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ require 'rubygems'
2
+ require 'vcr'
3
+ require 'webmock'
4
+ require 'dotenv/load'
5
+ require 'minitest/autorun'
6
+ require 'my_john_deere_api'
7
+
8
+ # shortcut for long module name
9
+ JD = MyJohnDeereApi
10
+
11
+ VCR.configure do |config|
12
+ config.cassette_library_dir = 'test/support/vcr'
13
+ config.hook_into :webmock
14
+ end
@@ -0,0 +1,46 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://sandboxapi.deere.com/platform/
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - application/vnd.deere.axiom.v3+json
12
+ Accept-Encoding:
13
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
14
+ User-Agent:
15
+ - OAuth gem v0.5.4
16
+ Authorization:
17
+ - OAuth oauth_consumer_key="johndeere-wgmADngYCRmfpEbVgSyc709wnyRux5J7PAv8SE7B",
18
+ oauth_nonce="hLAsNSIk6Q2d3ULD6bT6rVf10km1qN5edh9HvNUgSc", oauth_signature="wjrjTVSXWY3uanxn69Y251jDFn8%3D",
19
+ oauth_signature_method="HMAC-SHA1", oauth_timestamp="1578174980", oauth_version="1.0"
20
+ response:
21
+ status:
22
+ code: 200
23
+ message: OK
24
+ headers:
25
+ Date:
26
+ - Sat, 04 Jan 2020 21:56:21 GMT
27
+ Content-Type:
28
+ - application/vnd.deere.axiom.v3+json;charset=UTF-8
29
+ X-Deere-Handling-Server:
30
+ - ip-10-214-44-80
31
+ X-Frame-Options:
32
+ - SAMEORIGIN
33
+ X-Deere-Elapsed-Ms:
34
+ - '16'
35
+ Cache-Control:
36
+ - no-store
37
+ Content-Language:
38
+ - en-US
39
+ Transfer-Encoding:
40
+ - chunked
41
+ body:
42
+ encoding: ASCII-8BIT
43
+ string: '{"@type":"ApiCatalog","links":[{"@type":"Link","rel":"oauthRequestToken","uri":"https://sandboxapi.deere.com/platform/oauth/request_token"},{"@type":"Link","rel":"oauthAuthorizeRequestToken","uri":"https://my.deere.com/consentToUseOfData?oauth_token={token}"},{"@type":"Link","rel":"oauthAccessToken","uri":"https://sandboxapi.deere.com/platform/oauth/access_token"},{"@type":"Link","rel":"agencies","uri":"https://sandboxapi.deere.com/platform/agencies"}]}'
44
+ http_version:
45
+ recorded_at: Sat, 04 Jan 2020 21:56:21 GMT
46
+ recorded_with: VCR 5.0.0
@@ -0,0 +1,46 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://sandboxapi.deere.com/platform/
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - application/vnd.deere.axiom.v3+json
12
+ Accept-Encoding:
13
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
14
+ User-Agent:
15
+ - OAuth gem v0.5.4
16
+ Authorization:
17
+ - OAuth oauth_consumer_key="johndeere-wgmADngYCRmfpEbVgSyc709wnyRux5J7PAv8SE7B",
18
+ oauth_nonce="3O7ELJDsWLUeJWwOv38z2KBoobVksbYRYDspg7fpMyc", oauth_signature="TL0zdGeZxLQ%2BYKgQDqnZQ%2BBZsJA%3D",
19
+ oauth_signature_method="HMAC-SHA1", oauth_timestamp="1578166502", oauth_version="1.0"
20
+ response:
21
+ status:
22
+ code: 200
23
+ message: OK
24
+ headers:
25
+ Date:
26
+ - Sat, 04 Jan 2020 19:35:04 GMT
27
+ Content-Type:
28
+ - application/vnd.deere.axiom.v3+json;charset=UTF-8
29
+ X-Deere-Handling-Server:
30
+ - ip-10-214-44-145
31
+ X-Frame-Options:
32
+ - SAMEORIGIN
33
+ X-Deere-Elapsed-Ms:
34
+ - '11'
35
+ Cache-Control:
36
+ - no-store
37
+ Content-Language:
38
+ - en-US
39
+ Transfer-Encoding:
40
+ - chunked
41
+ body:
42
+ encoding: ASCII-8BIT
43
+ string: '{"@type":"ApiCatalog","links":[{"@type":"Link","rel":"oauthRequestToken","uri":"https://sandboxapi.deere.com/platform/oauth/request_token"},{"@type":"Link","rel":"oauthAuthorizeRequestToken","uri":"https://my.deere.com/consentToUseOfData?oauth_token={token}"},{"@type":"Link","rel":"oauthAccessToken","uri":"https://sandboxapi.deere.com/platform/oauth/access_token"},{"@type":"Link","rel":"agencies","uri":"https://sandboxapi.deere.com/platform/agencies"}]}'
44
+ http_version:
45
+ recorded_at: Sat, 04 Jan 2020 19:35:04 GMT
46
+ recorded_with: VCR 5.0.0
@@ -0,0 +1,83 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://sandboxapi.deere.com/platform/
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - application/vnd.deere.axiom.v3+json
12
+ Accept-Encoding:
13
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
14
+ User-Agent:
15
+ - OAuth gem v0.5.4
16
+ Authorization:
17
+ - OAuth oauth_consumer_key="johndeere-wgmADngYCRmfpEbVgSyc709wnyRux5J7PAv8SE7B",
18
+ oauth_nonce="bA9m9jeEEXtDVO6t3evCoJcxWV6ask0dqv90ULA", oauth_signature="URbHoE5qi3YLnZlA5FiS6mloDPE%3D",
19
+ oauth_signature_method="HMAC-SHA1", oauth_timestamp="1578170525", oauth_version="1.0"
20
+ response:
21
+ status:
22
+ code: 200
23
+ message: OK
24
+ headers:
25
+ Date:
26
+ - Sat, 04 Jan 2020 20:42:06 GMT
27
+ Content-Type:
28
+ - application/vnd.deere.axiom.v3+json;charset=UTF-8
29
+ X-Deere-Handling-Server:
30
+ - ip-10-214-45-13
31
+ X-Frame-Options:
32
+ - SAMEORIGIN
33
+ X-Deere-Elapsed-Ms:
34
+ - '14'
35
+ Cache-Control:
36
+ - no-store
37
+ Content-Language:
38
+ - en-US
39
+ Transfer-Encoding:
40
+ - chunked
41
+ body:
42
+ encoding: ASCII-8BIT
43
+ string: '{"@type":"ApiCatalog","links":[{"@type":"Link","rel":"oauthRequestToken","uri":"https://sandboxapi.deere.com/platform/oauth/request_token"},{"@type":"Link","rel":"oauthAuthorizeRequestToken","uri":"https://my.deere.com/consentToUseOfData?oauth_token={token}"},{"@type":"Link","rel":"oauthAccessToken","uri":"https://sandboxapi.deere.com/platform/oauth/access_token"},{"@type":"Link","rel":"agencies","uri":"https://sandboxapi.deere.com/platform/agencies"}]}'
44
+ http_version:
45
+ recorded_at: Sat, 04 Jan 2020 20:42:07 GMT
46
+ - request:
47
+ method: get
48
+ uri: https://sandboxapi.deere.com/platform/oauth/request_token
49
+ body:
50
+ encoding: US-ASCII
51
+ string: ''
52
+ headers:
53
+ Accept-Encoding:
54
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
55
+ Accept:
56
+ - "*/*"
57
+ User-Agent:
58
+ - OAuth gem v0.5.4
59
+ Authorization:
60
+ - OAuth oauth_callback="oob", oauth_consumer_key="johndeere-wgmADngYCRmfpEbVgSyc709wnyRux5J7PAv8SE7B",
61
+ oauth_nonce="D1Wa1SttrwCzWrFAAoEDUUyRmzVRkd6ka8rpAmWw8", oauth_signature="HciHAu%2Bojp4olApwEKk14WrhMt0%3D",
62
+ oauth_signature_method="HMAC-SHA1", oauth_timestamp="1578170527", oauth_version="1.0"
63
+ response:
64
+ status:
65
+ code: 200
66
+ message: OK
67
+ headers:
68
+ Date:
69
+ - Sat, 04 Jan 2020 20:42:07 GMT
70
+ Content-Type:
71
+ - text/plain;charset=UTF-8
72
+ X-Deere-Handling-Server:
73
+ - ip-10-214-45-13
74
+ Vary:
75
+ - Accept-Encoding
76
+ Transfer-Encoding:
77
+ - chunked
78
+ body:
79
+ encoding: ASCII-8BIT
80
+ string: oauth_token=27f8a03d-cda3-4b80-a42d-8f10065448e5&oauth_token_secret=mAsr2Tfy4YGUOrZG1%2BhIMefCIqom1yCQ90mXsQm7TOEjh%2B3HpRKgif8DrCdhNcKB31lpZqKbxX%2FKSD3xseT1BsFeFRlJPADHGd78B1mWtJI%3D&oauth_callback_confirmed=true
81
+ http_version:
82
+ recorded_at: Sat, 04 Jan 2020 20:42:08 GMT
83
+ recorded_with: VCR 5.0.0
@@ -1,10 +1,13 @@
1
- require 'minitest/autorun'
2
- require 'my_john_deere_api'
1
+ require 'support/helper'
3
2
 
4
3
  class MyJohnDeereApiTest < MiniTest::Test
5
- describe 'VERSION' do
6
- it 'conforms to the semantic version format' do
7
- assert_match /^\d+\.\d+\.\d+$/, MyJohnDeereApi::VERSION
4
+ describe 'loading dependencies' do
5
+ it 'loads VERSION' do
6
+ assert JD::VERSION
7
+ end
8
+
9
+ it 'loads Authorize' do
10
+ assert JD::Authorize
8
11
  end
9
12
  end
10
13
  end
metadata CHANGED
@@ -1,15 +1,85 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: my_john_deere_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jaime. Bellmyer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-01-04 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2020-01-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: vcr
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '5.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '5.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: dotenv
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 2.7.5
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 2.7.5
41
+ - !ruby/object:Gem::Dependency
42
+ name: webmock
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 3.7.6
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 3.7.6
55
+ - !ruby/object:Gem::Dependency
56
+ name: oauth
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.5.4
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.5.4
69
+ - !ruby/object:Gem::Dependency
70
+ name: json
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 2.1.0
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 2.1.0
13
83
  description: |
14
84
  == My John Deere API
15
85
 
@@ -26,7 +96,14 @@ files:
26
96
  - README.md
27
97
  - Rakefile
28
98
  - lib/my_john_deere_api.rb
99
+ - lib/my_john_deere_api/authorize.rb
29
100
  - lib/my_john_deere_api/version.rb
101
+ - test/lib/test_authorize.rb
102
+ - test/lib/test_version.rb
103
+ - test/support/helper.rb
104
+ - test/support/vcr/app_consumer.yml
105
+ - test/support/vcr/catalog.yml
106
+ - test/support/vcr/get_request_token.yml
30
107
  - test/test_my_john_deere_api.rb
31
108
  homepage: https://github.com/Intellifarm/my_john_deere_api
32
109
  licenses: