zendesk2 0.0.4 → 0.0.5
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/.travis.yml +7 -0
- data/Gemfile +2 -0
- data/README.md +133 -6
- data/Rakefile +5 -0
- data/lib/zendesk2/client.rb +10 -14
- data/lib/zendesk2/models/organization.rb +9 -9
- data/lib/zendesk2/models/ticket.rb +14 -14
- data/lib/zendesk2/models/user.rb +52 -15
- data/lib/zendesk2/paged_collection.rb +4 -3
- data/lib/zendesk2/requests/get_organization_tickets.rb +2 -2
- data/lib/zendesk2/requests/get_organization_users.rb +1 -1
- data/lib/zendesk2/requests/update_user.rb +2 -0
- data/lib/zendesk2/version.rb +1 -1
- data/lib/zendesk2.rb +4 -2
- data/spec/shared/resource.rb +4 -4
- data/spec/users_spec.rb +2 -2
- metadata +3 -3
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# Zendesk2
|
2
2
|
|
3
|
-
|
3
|
+
[](http://travis-ci.org/lanej/zendesk2)
|
4
|
+
|
5
|
+
Ruby client for the [Zendesk V2 API](http://developer.zendesk.com/documentation/rest_api/introduction.html) using [cistern](https://github.com/lanej/cistern) and [faraday](https://github.com/technoweenie/faraday)
|
4
6
|
|
5
7
|
## Installation
|
6
8
|
|
@@ -8,17 +10,142 @@ Add this line to your application's Gemfile:
|
|
8
10
|
|
9
11
|
gem 'zendesk2'
|
10
12
|
|
11
|
-
And then execute:
|
12
|
-
|
13
|
-
$ bundle
|
14
|
-
|
15
13
|
Or install it yourself as:
|
16
14
|
|
17
15
|
$ gem install zendesk2
|
18
16
|
|
19
17
|
## Usage
|
20
18
|
|
21
|
-
|
19
|
+
### Defaults
|
20
|
+
|
21
|
+
Default credentials will be read in from `~/.zendesk2` file in YAML format.
|
22
|
+
|
23
|
+
---
|
24
|
+
:subdomain: zendeskdev
|
25
|
+
:username: zendeskedge@example.com
|
26
|
+
:password: wickedsecurepassword
|
27
|
+
|
28
|
+
### Creating the client
|
29
|
+
|
30
|
+
Either the absolute url or the subdomain is required. Username and password is always required.
|
31
|
+
|
32
|
+
Zendesk2::Client.new(subdomain: "engineyard", username: "orchestra", password: "gwoo")
|
33
|
+
=> #<Zendesk2::Client::Real:0x007f99da1f9430 @url="https://engineyard.zendesk.com/api/v2", @username="orchestra", @password="gwoo", …>
|
34
|
+
|
35
|
+
or
|
36
|
+
|
37
|
+
=> #<Zendesk2::Client::Real:0x007fd1bae486b0 @url="http://support.cloud.engineyard.com", @username="mate", @password="bambilla", …>
|
38
|
+
|
39
|
+
### Resources
|
40
|
+
|
41
|
+
#### Collections
|
42
|
+
|
43
|
+
Currently support resources
|
44
|
+
|
45
|
+
* User
|
46
|
+
* Ticket
|
47
|
+
* Organization
|
48
|
+
|
49
|
+
All collection are accessed like so:
|
50
|
+
|
51
|
+
client.users.all
|
52
|
+
=> <Zendesk2::Client::Users
|
53
|
+
count=1779,
|
54
|
+
next_page_link="https://dev.zendesk.com/api/v2/users.json?page=2",
|
55
|
+
previous_page_link=nil
|
56
|
+
[
|
57
|
+
<Zendesk2::Client::User
|
58
|
+
id=125394183,
|
59
|
+
url="https://dev.zendesk.com/api/v2/users/125394183.json",
|
60
|
+
...
|
61
|
+
>
|
62
|
+
]
|
63
|
+
|
64
|
+
Collections also respond to `create` and `new`
|
65
|
+
|
66
|
+
client.users.create(email: "ohhai@example.org", name: "lulz")
|
67
|
+
=> <Zendesk2::Client::User
|
68
|
+
id=234020811,
|
69
|
+
...
|
70
|
+
url="https://engineyarddev.zendesk.com/api/v2/users/234020811.json",
|
71
|
+
...
|
72
|
+
email="ohhai@example.org",
|
73
|
+
>
|
74
|
+
|
75
|
+
|
76
|
+
client.users.new(email: "ohhai@example.org")
|
77
|
+
=> <Zendesk2::Client::User
|
78
|
+
id=nil,
|
79
|
+
...
|
80
|
+
url=nil,
|
81
|
+
...
|
82
|
+
email="ohhai@example.org",
|
83
|
+
...
|
84
|
+
>
|
85
|
+
|
86
|
+
#### Paging
|
87
|
+
|
88
|
+
Paged collections respond to `next_page` and `previous_page` when appropriate. `page_size` and `page` can be passed directly to the collection to control size and index.
|
89
|
+
|
90
|
+
page = client.users.all("per_page" => 1, "page" => 4)
|
91
|
+
=> <Zendesk2::Client::Users
|
92
|
+
count=1780,
|
93
|
+
next_page_link="https://dev.zendesk.com/api/v2/users.json?page=5&per_page=1",
|
94
|
+
previous_page_link="https://dev.zendesk.com/api/v2/users.json?page=3&per_page=1"
|
95
|
+
[
|
96
|
+
<Zendesk2::Client::User
|
97
|
+
id=217761652,
|
98
|
+
url="https://dev.zendesk.com/api/v2/users/217761652.json",
|
99
|
+
external_id=nil,
|
100
|
+
name="Guy Dude",
|
101
|
+
...
|
102
|
+
>
|
103
|
+
]
|
104
|
+
|
105
|
+
page.next_page
|
106
|
+
=> <Zendesk2::Client::Users
|
107
|
+
count=1780,
|
108
|
+
next_page_link="https://dev.zendesk.com/api/v2/users.json?page=6&per_page=1",
|
109
|
+
previous_page_link="https://dev.zendesk.com/api/v2/users.json?page=4&per_page=1"
|
110
|
+
[
|
111
|
+
<Zendesk2::Client::User
|
112
|
+
id=217761742,
|
113
|
+
url="https://dev.zendesk.com/api/v2/users/217761742.json",
|
114
|
+
...
|
115
|
+
name="epitaphical osteofibrous",
|
116
|
+
...
|
117
|
+
>
|
118
|
+
]
|
119
|
+
|
120
|
+
page.previous_page
|
121
|
+
=> <Zendesk2::Client::Users
|
122
|
+
count=1780,
|
123
|
+
next_page_link="https://dev.zendesk.com/api/v2/users.json?page=5&per_page=1",
|
124
|
+
previous_page_link="https://dev.zendesk.com/api/v2/users.json?page=3&per_page=1"
|
125
|
+
[
|
126
|
+
<Zendesk2::Client::User
|
127
|
+
id=217761652,
|
128
|
+
url="https://dev.zendesk.com/api/v2/users/217761652.json",
|
129
|
+
...
|
130
|
+
name="Guy Dude",
|
131
|
+
...
|
132
|
+
>
|
133
|
+
]
|
134
|
+
|
135
|
+
#### Models
|
136
|
+
|
137
|
+
All models respond to `destroy` and `save` if applicable. `save` performs a 'create' operation if there is no identity provided or an 'update' if there is an identity.
|
138
|
+
|
139
|
+
Zendesk2::Client::Ticket.new.save # performs a create
|
140
|
+
Zendesk2::Client::Ticket.new(id: 1).save # performs an update
|
141
|
+
|
142
|
+
Attributes can be enumerated by the `attributes` method.
|
143
|
+
|
144
|
+
## Releasing
|
145
|
+
|
146
|
+
|
147
|
+
$ gem install gem-release
|
148
|
+
$ gem bump -trv (major|minor|patch)
|
22
149
|
|
23
150
|
## Contributing
|
24
151
|
|
data/Rakefile
CHANGED
data/lib/zendesk2/client.rb
CHANGED
@@ -29,7 +29,7 @@ class Zendesk2::Client < Cistern::Service
|
|
29
29
|
request :update_ticket
|
30
30
|
request :update_user
|
31
31
|
|
32
|
-
recognizes :url, :subdomain, :host, :port, :path, :scheme, :logger, :adapter
|
32
|
+
recognizes :url, :subdomain, :host, :port, :path, :scheme, :logger, :adapter, :username, :password, :token
|
33
33
|
|
34
34
|
class Real
|
35
35
|
|
@@ -42,28 +42,28 @@ class Zendesk2::Client < Cistern::Service
|
|
42
42
|
|
43
43
|
host ||= "#{subdomain}.zendesk.com"
|
44
44
|
|
45
|
-
|
45
|
+
path = options[:path] || "api/v2"
|
46
46
|
scheme = options[:scheme] || "https"
|
47
47
|
|
48
48
|
port = options[:port] || (scheme == "https" ? 443 : 80)
|
49
49
|
|
50
|
-
"#{scheme}://#{host}:#{port}/#{
|
50
|
+
"#{scheme}://#{host}:#{port}/#{path}"
|
51
51
|
end
|
52
52
|
|
53
|
-
@url = url
|
54
|
-
@path ||= URI.parse(url).path
|
53
|
+
@url = URI.parse(url).to_s
|
55
54
|
|
56
55
|
logger = options[:logger]
|
57
56
|
adapter = options[:adapter] || :net_http
|
58
57
|
connection_options = options[:connection_options] || {ssl: {verify: false}}
|
59
|
-
|
60
|
-
|
58
|
+
username = options[:username] || Zendesk2.defaults[:username]
|
59
|
+
password = options[:password] || Zendesk2.defaults[:password]
|
60
|
+
@token = options[:token]
|
61
61
|
|
62
|
-
raise "Missing required options: [:username, :password]" unless
|
62
|
+
raise "Missing required options: [:username, :password]" unless username && password
|
63
63
|
|
64
64
|
@connection = Faraday.new({url: @url}.merge(connection_options)) do |builder|
|
65
65
|
# response
|
66
|
-
builder.use Faraday::Request::BasicAuthentication,
|
66
|
+
builder.use Faraday::Request::BasicAuthentication, username, password
|
67
67
|
builder.use Faraday::Response::RaiseError
|
68
68
|
builder.use Faraday::Response::Logger, logger if logger
|
69
69
|
builder.response :json
|
@@ -163,13 +163,9 @@ class Zendesk2::Client < Cistern::Service
|
|
163
163
|
|
164
164
|
next_page = if page_index < total_pages
|
165
165
|
url_for("#{path}?page=#{page_index + 1}&per_page=#{page_size}")
|
166
|
-
else
|
167
|
-
nil
|
168
166
|
end
|
169
167
|
previous_page = if page_index > 1
|
170
168
|
url_for("#{path}?page=#{page_index - 1}&per_page=#{page_size}")
|
171
|
-
else
|
172
|
-
nil
|
173
169
|
end
|
174
170
|
|
175
171
|
resource_page = resources.slice(offset, page_size)
|
@@ -201,7 +197,7 @@ class Zendesk2::Client < Cistern::Service
|
|
201
197
|
:url => url,
|
202
198
|
:body => body,
|
203
199
|
:request_headers => {
|
204
|
-
"Content-Type" => "application/json"
|
200
|
+
"Content-Type" => "application/json; charset=utf-8"
|
205
201
|
},
|
206
202
|
)
|
207
203
|
end
|
@@ -1,17 +1,17 @@
|
|
1
1
|
class Zendesk2::Client::Organization < Cistern::Model
|
2
2
|
include Zendesk2::Errors
|
3
|
-
identity :id
|
4
|
-
attribute :shared_comments
|
5
|
-
attribute :notes
|
3
|
+
identity :id, type: :integer
|
4
|
+
attribute :shared_comments, type: :boolean
|
5
|
+
attribute :notes, type: :array
|
6
6
|
attribute :tags
|
7
|
-
attribute :domain_names
|
8
|
-
attribute :group_id
|
9
|
-
attribute :external_id
|
7
|
+
attribute :domain_names, type: :array
|
8
|
+
attribute :group_id, type: :integer
|
9
|
+
attribute :external_id, type: :integer
|
10
10
|
attribute :name
|
11
|
-
attribute :created_at,
|
11
|
+
attribute :created_at, type: :time
|
12
12
|
attribute :details
|
13
|
-
attribute :shared_tickets
|
14
|
-
attribute :updated_at,
|
13
|
+
attribute :shared_tickets, type: :boolean
|
14
|
+
attribute :updated_at, type: :time
|
15
15
|
|
16
16
|
def destroy
|
17
17
|
requires :identity
|
@@ -1,28 +1,28 @@
|
|
1
1
|
class Zendesk2::Client::Ticket < Cistern::Model
|
2
2
|
include Zendesk2::Errors
|
3
|
-
identity :id
|
3
|
+
identity :id, type: :id
|
4
4
|
attribute :external_id
|
5
5
|
attribute :via
|
6
|
-
attribute :created_at,
|
7
|
-
attribute :updated_at,
|
6
|
+
attribute :created_at, type: :time
|
7
|
+
attribute :updated_at, type: :time
|
8
8
|
attribute :type
|
9
9
|
attribute :subject
|
10
10
|
attribute :description
|
11
11
|
attribute :priority
|
12
12
|
attribute :status
|
13
13
|
attribute :recipient
|
14
|
-
attribute :requester_id
|
15
|
-
attribute :submitter_id
|
16
|
-
attribute :assignee_id
|
17
|
-
attribute :organization_id
|
18
|
-
attribute :group_id
|
14
|
+
attribute :requester_id, type: :integer
|
15
|
+
attribute :submitter_id, type: :integer
|
16
|
+
attribute :assignee_id, type: :integer
|
17
|
+
attribute :organization_id, type: :integer
|
18
|
+
attribute :group_id, type: :integer
|
19
19
|
attribute :collaborator_ids, type: :array
|
20
|
-
attribute :forum_topic_id
|
21
|
-
attribute :problem_id
|
22
|
-
attribute :has_incidents
|
23
|
-
attribute :due_at,
|
24
|
-
attribute :tags,
|
25
|
-
attribute :fields
|
20
|
+
attribute :forum_topic_id, type: :integer
|
21
|
+
attribute :problem_id, type: :integer
|
22
|
+
attribute :has_incidents, type: :boolean
|
23
|
+
attribute :due_at, type: :time
|
24
|
+
attribute :tags, type: :array
|
25
|
+
attribute :fields, type: :array
|
26
26
|
|
27
27
|
def save
|
28
28
|
if new_record?
|
data/lib/zendesk2/models/user.rb
CHANGED
@@ -1,31 +1,31 @@
|
|
1
1
|
class Zendesk2::Client::User < Cistern::Model
|
2
|
-
identity :id
|
2
|
+
identity :id, type: :id
|
3
3
|
attribute :url
|
4
4
|
attribute :external_id
|
5
5
|
attribute :name
|
6
6
|
attribute :alias
|
7
|
-
attribute :created_at,
|
8
|
-
attribute :updated_at,
|
9
|
-
attribute :active,
|
10
|
-
attribute :verified,
|
11
|
-
attribute :shared
|
12
|
-
attribute :locale_id
|
7
|
+
attribute :created_at, type: :time
|
8
|
+
attribute :updated_at, type: :time
|
9
|
+
attribute :active, type: :boolean
|
10
|
+
attribute :verified, type: :boolean
|
11
|
+
attribute :shared, type: :boolean
|
12
|
+
attribute :locale_id, type: :integer
|
13
13
|
attribute :locale
|
14
14
|
attribute :time_zone
|
15
|
-
attribute :last_login_at,
|
15
|
+
attribute :last_login_at, type: :time
|
16
16
|
attribute :email
|
17
17
|
attribute :phone
|
18
18
|
attribute :signature
|
19
19
|
attribute :details
|
20
20
|
attribute :notes
|
21
|
-
attribute :organization_id
|
21
|
+
attribute :organization_id, type: :integer
|
22
22
|
attribute :role
|
23
|
-
attribute :custom_role_id
|
24
|
-
attribute :moderator
|
23
|
+
attribute :custom_role_id, type: :integer
|
24
|
+
attribute :moderator, type: :boolean
|
25
25
|
attribute :ticket_restriction
|
26
|
-
attribute :only_private_comments
|
27
|
-
attribute :tags
|
28
|
-
attribute :suspended
|
26
|
+
attribute :only_private_comments, type: :boolean
|
27
|
+
attribute :tags, type: :array
|
28
|
+
attribute :suspended, type: :boolean
|
29
29
|
attribute :photo
|
30
30
|
attribute :authenticity_token
|
31
31
|
|
@@ -53,9 +53,46 @@ class Zendesk2::Client::User < Cistern::Model
|
|
53
53
|
!self.active
|
54
54
|
end
|
55
55
|
|
56
|
+
def organization=(organization)
|
57
|
+
self.organization_id= organization.id
|
58
|
+
end
|
59
|
+
|
60
|
+
def organization
|
61
|
+
self.connection.organizations.get(self.organization_id)
|
62
|
+
end
|
63
|
+
|
64
|
+
def login_url(timestamp, options={})
|
65
|
+
requires :name, :email
|
66
|
+
|
67
|
+
return_to = options[:return_to]
|
68
|
+
token = self.token || options[:token]
|
69
|
+
|
70
|
+
uri = Addressable::URI.parse(self.connection.url)
|
71
|
+
uri.path = "/access/remote"
|
72
|
+
|
73
|
+
raise "timestamp cannot be nil" unless timestamp
|
74
|
+
|
75
|
+
hash_str = "#{self.name}#{self.email}#{token}#{timestamp}"
|
76
|
+
query_values = {
|
77
|
+
'name' => name,
|
78
|
+
'email' => email,
|
79
|
+
'timestamp' => timestamp,
|
80
|
+
'hash' => Digest::MD5.hexdigest(hash_str)
|
81
|
+
}
|
82
|
+
unless Zendesk2.blank?(return_to)
|
83
|
+
query_values['return_to'] = return_to
|
84
|
+
end
|
85
|
+
uri.query_values = query_values
|
86
|
+
|
87
|
+
uri.to_s
|
88
|
+
end
|
89
|
+
|
56
90
|
private
|
57
91
|
|
58
92
|
def params
|
59
|
-
Cistern::Hash.slice(Zendesk2.stringify_keys(attributes), "name", "email", "organization_id", "external_id", "alias", "
|
93
|
+
writable_attributes = Cistern::Hash.slice(Zendesk2.stringify_keys(attributes), "name", "email", "organization_id", "external_id", "alias", "verified", "locate_id", "time_zone", "phone", "signature", "details", "notes", "role", "custom_role_id", "moderator", "ticket_restriction", "only_private_comments")
|
94
|
+
writable_attributes.delete("organization_id") if writable_attributes["organization_id"] == 0
|
95
|
+
writable_attributes.delete("custom_role_id") if writable_attributes["custom_role_id"] == 0
|
96
|
+
writable_attributes
|
60
97
|
end
|
61
98
|
end
|
@@ -14,12 +14,13 @@ module Zendesk2::PagedCollection
|
|
14
14
|
def all(params={})
|
15
15
|
body = connection.send(collection_method, params).body
|
16
16
|
|
17
|
-
load(body[collection_root])
|
18
|
-
merge_attributes(Cistern::Hash.slice(body, "count", "next_page", "previous_page"))
|
17
|
+
collection = self.clone.load(body[collection_root])
|
18
|
+
collection.merge_attributes(Cistern::Hash.slice(body, "count", "next_page", "previous_page"))
|
19
|
+
collection
|
19
20
|
end
|
20
21
|
|
21
22
|
def get(id)
|
22
|
-
if data = connection.send(model_method, {"id" => id}).body[self.model_root]
|
23
|
+
if data = self.connection.send(model_method, {"id" => id}).body[self.model_root]
|
23
24
|
new(data)
|
24
25
|
end
|
25
26
|
end
|
@@ -16,8 +16,8 @@ class Zendesk2::Client
|
|
16
16
|
def get_organization_tickets(params={})
|
17
17
|
id = params["id"]
|
18
18
|
|
19
|
-
requesters = self.data[:users].values.select{|u| u["organization_id"]
|
20
|
-
page(params, :tickets, "/organizations/#{id}/tickets.json", "tickets", filter: lambda{|c| c.select{|u| requesters.include?(u["organization_id"]
|
19
|
+
requesters = self.data[:users].values.select{|u| u["organization_id"] == id}.map{|s| s["organization_id"]}
|
20
|
+
page(params, :tickets, "/organizations/#{id}/tickets.json", "tickets", filter: lambda{|c| c.select{|u| requesters.include?(u["organization_id"])}})
|
21
21
|
end
|
22
22
|
end # Mock
|
23
23
|
end
|
@@ -15,7 +15,7 @@ class Zendesk2::Client
|
|
15
15
|
class Mock
|
16
16
|
def get_organization_users(params={})
|
17
17
|
id = params["id"]
|
18
|
-
page(params, :users, "/organizations/#{id}/users.json", "users", filter: lambda{|c| c.select{|u| u["organization_id"]
|
18
|
+
page(params, :users, "/organizations/#{id}/users.json", "users", filter: lambda{|c| c.select{|u| u["organization_id"] == id}})
|
19
19
|
end
|
20
20
|
end # Mock
|
21
21
|
end
|
data/lib/zendesk2/version.rb
CHANGED
data/lib/zendesk2.rb
CHANGED
data/spec/shared/resource.rb
CHANGED
@@ -17,14 +17,14 @@ shared_examples "a resource" do |_collection, _params, _update_params|
|
|
17
17
|
end
|
18
18
|
|
19
19
|
it "by retrieving the next page" do
|
20
|
-
first_page = collection.all("per_page" =>
|
21
|
-
second_page = collection.all("per_page" => 1).next_page
|
20
|
+
first_page = collection.all("per_page" => 1)
|
21
|
+
second_page = collection.all("per_page" => 1).next_page
|
22
22
|
second_page.should_not == first_page
|
23
23
|
end
|
24
24
|
|
25
25
|
it "by retrieving the previous page" do
|
26
|
-
first_page = collection.all("per_page" => "1")
|
27
|
-
previous_to_second_page = collection.all("per_page" => 1).next_page.previous_page
|
26
|
+
first_page = collection.all("per_page" => "1")
|
27
|
+
previous_to_second_page = collection.all("per_page" => 1).next_page.previous_page
|
28
28
|
previous_to_second_page.should == first_page
|
29
29
|
end
|
30
30
|
end
|
data/spec/users_spec.rb
CHANGED
@@ -4,8 +4,8 @@ describe "users" do
|
|
4
4
|
let(:client) { create_client }
|
5
5
|
it_should_behave_like "a resource",
|
6
6
|
:users,
|
7
|
-
lambda { {email: "zendesk2+#{Zendesk2.uuid}@example.org", name:
|
8
|
-
lambda { {name:
|
7
|
+
lambda { {email: "zendesk2+#{Zendesk2.uuid}@example.org", name: Zendesk2.uuid, verified: true} },
|
8
|
+
lambda { {name: Zendesk2.uuid} }
|
9
9
|
|
10
10
|
it "should get current user" do
|
11
11
|
current_user = client.users.current
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zendesk2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-07-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: cistern
|
@@ -100,6 +100,7 @@ extra_rdoc_files: []
|
|
100
100
|
files:
|
101
101
|
- .gitignore
|
102
102
|
- .rspec
|
103
|
+
- .travis.yml
|
103
104
|
- Gemfile
|
104
105
|
- Guardfile
|
105
106
|
- LICENSE
|
@@ -172,4 +173,3 @@ test_files:
|
|
172
173
|
- spec/support/client_helper.rb
|
173
174
|
- spec/tickets_spec.rb
|
174
175
|
- spec/users_spec.rb
|
175
|
-
has_rdoc:
|