dnsimple-ruby 1.3.2 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +9 -2
  3. data/.rspec +1 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +7 -0
  7. data/CHANGELOG.md +20 -0
  8. data/Gemfile +0 -2
  9. data/LICENSE +2 -2
  10. data/README.md +121 -0
  11. data/Rakefile +30 -14
  12. data/bin/dnsimple.rb +1 -1
  13. data/dnsimple-ruby.gemspec +9 -8
  14. data/features/README +1 -1
  15. data/features/step_definitions/cli_steps.rb +1 -1
  16. data/features/support/env.rb +4 -4
  17. data/fixtures/vcr_cassettes/DNSimple_Certificate/_all.yml +45 -32
  18. data/fixtures/vcr_cassettes/DNSimple_Certificate/_purchase.yml +45 -32
  19. data/fixtures/vcr_cassettes/DNSimple_Certificate/_submit.yml +45 -32
  20. data/fixtures/vcr_cassettes/DNSimple_Contact/a_new_contact.yml +39 -31
  21. data/fixtures/vcr_cassettes/DNSimple_Contact/an_existing_contact.yml +39 -31
  22. data/fixtures/vcr_cassettes/DNSimple_Domain/_all.yml +113 -94
  23. data/fixtures/vcr_cassettes/DNSimple_Domain/applying_templates.yml +186 -156
  24. data/fixtures/vcr_cassettes/DNSimple_Domain/creating_a_new_domain.yml +39 -32
  25. data/fixtures/vcr_cassettes/DNSimple_Domain/finding_an_existing_domain/by_id.yml +39 -32
  26. data/fixtures/vcr_cassettes/DNSimple_Domain/finding_an_existing_domain/by_name.yml +39 -32
  27. data/fixtures/vcr_cassettes/DNSimple_Domain/registration/with_a_new_registrant_contact.yml +40 -32
  28. data/fixtures/vcr_cassettes/DNSimple_Domain/registration/with_an_existing_contact.yml +40 -32
  29. data/fixtures/vcr_cassettes/DNSimple_ExtendedAttribute/list_extended_attributes/for_ca.yml +262 -29
  30. data/fixtures/vcr_cassettes/DNSimple_ExtendedAttribute/list_extended_attributes/for_com.yml +35 -29
  31. data/fixtures/vcr_cassettes/DNSimple_Record/_all.yml +147 -125
  32. data/fixtures/vcr_cassettes/DNSimple_Record/creating_a_new_record.yml +39 -32
  33. data/fixtures/vcr_cassettes/DNSimple_Record/find_a_record.yml +39 -32
  34. data/fixtures/vcr_cassettes/DNSimple_Template/a_template.yml +41 -32
  35. data/fixtures/vcr_cassettes/DNSimple_User/_me.yml +38 -31
  36. data/lib/dnsimple.rb +14 -1
  37. data/lib/dnsimple/base.rb +7 -5
  38. data/lib/dnsimple/certificate.rb +100 -95
  39. data/lib/dnsimple/cli.rb +92 -93
  40. data/lib/dnsimple/client.rb +109 -99
  41. data/lib/dnsimple/commands/{describe_certificate.rb → certificate_describe.rb} +2 -2
  42. data/lib/dnsimple/commands/{list_certificates.rb → certificate_list.rb} +2 -2
  43. data/lib/dnsimple/commands/{purchase_certificate.rb → certificate_purchase.rb} +3 -5
  44. data/lib/dnsimple/commands/{submit_certificate.rb → certificate_submit.rb} +3 -5
  45. data/lib/dnsimple/commands/{create_contact.rb → contact_create.rb} +8 -6
  46. data/lib/dnsimple/commands/{delete_contact.rb → contact_delete.rb} +2 -2
  47. data/lib/dnsimple/commands/{describe_contact.rb → contact_describe.rb} +2 -2
  48. data/lib/dnsimple/commands/{list_contacts.rb → contact_list.rb} +2 -2
  49. data/lib/dnsimple/commands/{update_contact.rb → contact_update.rb} +2 -2
  50. data/lib/dnsimple/commands/{apply_template.rb → domain_apply_template.rb} +2 -2
  51. data/lib/dnsimple/commands/{check_domain.rb → domain_check.rb} +2 -2
  52. data/lib/dnsimple/commands/{clear_domain.rb → domain_clear.rb} +2 -2
  53. data/lib/dnsimple/commands/{create_domain.rb → domain_create.rb} +2 -2
  54. data/lib/dnsimple/commands/{delete_domain.rb → domain_delete.rb} +2 -2
  55. data/lib/dnsimple/commands/{describe_domain.rb → domain_describe.rb} +2 -2
  56. data/lib/dnsimple/commands/{list_domains.rb → domain_list.rb} +2 -2
  57. data/lib/dnsimple/commands/{register_domain.rb → domain_register.rb} +2 -2
  58. data/lib/dnsimple/commands/{transfer_domain.rb → domain_transfer.rb} +2 -2
  59. data/lib/dnsimple/commands/{list_extended_attributes.rb → extended_attribute_list.rb} +2 -2
  60. data/lib/dnsimple/commands/{describe_user.rb → me.rb} +2 -2
  61. data/lib/dnsimple/commands/{create_record.rb → record_create.rb} +5 -7
  62. data/lib/dnsimple/commands/{delete_record.rb → record_delete.rb} +2 -2
  63. data/lib/dnsimple/commands/{describe_record.rb → record_describe.rb} +2 -2
  64. data/lib/dnsimple/commands/{list_records.rb → record_list.rb} +4 -6
  65. data/lib/dnsimple/commands/{update_record.rb → record_update.rb} +2 -2
  66. data/lib/dnsimple/commands/{add_service.rb → service_add.rb} +3 -5
  67. data/lib/dnsimple/commands/{describe_service.rb → service_describe.rb} +2 -2
  68. data/lib/dnsimple/commands/{list_services.rb → service_list.rb} +2 -2
  69. data/lib/dnsimple/commands/{list_applied_services.rb → service_list_applied.rb} +2 -2
  70. data/lib/dnsimple/commands/{list_available_services.rb → service_list_available.rb} +2 -2
  71. data/lib/dnsimple/commands/{remove_service.rb → service_remove.rb} +2 -2
  72. data/lib/dnsimple/commands/{create_template.rb → template_create.rb} +2 -2
  73. data/lib/dnsimple/commands/{delete_template.rb → template_delete.rb} +2 -2
  74. data/lib/dnsimple/commands/{add_template_record.rb → template_record_create.rb} +2 -2
  75. data/lib/dnsimple/commands/{delete_template_record.rb → template_record_delete.rb} +2 -2
  76. data/lib/dnsimple/commands/{list_template_records.rb → template_record_list.rb} +2 -2
  77. data/lib/dnsimple/commands/{list_templates.rb → templates_list.rb} +2 -2
  78. data/lib/dnsimple/contact.rb +115 -110
  79. data/lib/dnsimple/domain.rb +134 -132
  80. data/lib/dnsimple/error.rb +8 -19
  81. data/lib/dnsimple/extended_attribute.rb +39 -33
  82. data/lib/dnsimple/record.rb +71 -67
  83. data/lib/dnsimple/service.rb +31 -24
  84. data/lib/dnsimple/template.rb +52 -46
  85. data/lib/dnsimple/template_record.rb +61 -53
  86. data/lib/dnsimple/transfer_order.rb +24 -18
  87. data/lib/dnsimple/user.rb +22 -18
  88. data/lib/dnsimple/version.rb +1 -1
  89. data/spec/README +1 -1
  90. data/spec/ci/.dnsimple.test +3 -0
  91. data/spec/commands/{purchase_certificate_spec.rb → certificate_purchase_spec.rb} +3 -4
  92. data/spec/commands/{submit_certificate_spec.rb → certificate_submit_spec.rb} +3 -4
  93. data/spec/commands/{create_record_spec.rb → record_create_spec.rb} +4 -4
  94. data/spec/commands/{list_records_spec.rb → records_list_spec.rb} +2 -13
  95. data/spec/commands/{add_service_spec.rb → service_add_spec.rb} +3 -12
  96. data/spec/{certificate_spec.rb → dnsimple/certificate_spec.rb} +0 -0
  97. data/spec/dnsimple/client_spec.rb +45 -18
  98. data/spec/{contact_spec.rb → dnsimple/contact_spec.rb} +3 -1
  99. data/spec/{domain_spec.rb → dnsimple/domain_spec.rb} +2 -0
  100. data/spec/{extended_attributes_spec.rb → dnsimple/extended_attributes_spec.rb} +4 -0
  101. data/spec/{record_spec.rb → dnsimple/record_spec.rb} +2 -0
  102. data/spec/{template_spec.rb → dnsimple/template_spec.rb} +0 -0
  103. data/spec/{user_spec.rb → dnsimple/user_spec.rb} +2 -0
  104. data/spec/spec_helper.rb +24 -10
  105. metadata +96 -99
  106. data/Gemfile.lock +0 -71
  107. data/README +0 -108
  108. data/README.rdoc +0 -108
  109. data/README.textile +0 -138
  110. data/lib/dnsimple/command.rb +0 -10
  111. data/spec/command_spec.rb +0 -19
@@ -1,32 +1,21 @@
1
1
  module DNSimple
2
+
2
3
  class Error < StandardError
3
4
  end
4
5
 
5
- class DomainError < DNSimple::Error
6
- def initialize(domain, messages)
7
- @domain = domain
8
- @messages = messages
9
- super "An error occurred: #{messages}"
10
- end
6
+ class RecordExists < Error
11
7
  end
12
8
 
13
- class RecordExists < DomainError
14
- def initialize(domain, message)
15
- super(domain, message)
16
- end
9
+ class RecordNotFound < Error
17
10
  end
18
11
 
19
- class RecordNotFound < DNSimple::Error; end
20
-
21
- class AuthenticationFailed < DNSimple::Error
22
- def initialize(message="Authentication failed")
23
- super(message)
12
+ class RequestError < Error
13
+ def initialize(description, response)
14
+ super("#{description}: #{response["error"]}")
24
15
  end
25
16
  end
26
17
 
27
- class UserNotFound < DNSimple::Error; end
28
-
29
- class CertificateExists < DNSimple::Error; end
18
+ class AuthenticationFailed < Error
19
+ end
30
20
 
31
- class CertificateNotFound < DNSimple::Error; end
32
21
  end
@@ -1,46 +1,52 @@
1
- class DNSimple::ExtendedAttribute < DNSimple::Base # Used for domains that require extended attributes.
2
- # An option for an extended attribute
3
- class Option < DNSimple::Base
4
- # The option name
5
- attr_accessor :title
1
+ module DNSimple
6
2
 
7
- # The option value
8
- attr_accessor :value
3
+ # Used for domains that require extended attributes.
4
+ class ExtendedAttribute < Base
9
5
 
10
- # A long description of the option
11
- attr_accessor :description
12
- end
6
+ # An option for an extended attribute
7
+ class Option < Base
8
+ # The option name
9
+ attr_accessor :title
13
10
 
14
- # The extended attribute name
15
- attr_accessor :name
11
+ # The option value
12
+ attr_accessor :value
16
13
 
17
- # A description of the extended attribute
18
- attr_accessor :description
14
+ # A long description of the option
15
+ attr_accessor :description
16
+ end
19
17
 
20
- # Boolean indicating if the extended attribute is required
21
- attr_accessor :required
18
+ # The extended attribute name
19
+ attr_accessor :name
22
20
 
23
- # An array of options for the extended attribute
24
- def options
25
- @options ||= []
26
- end
21
+ # A description of the extended attribute
22
+ attr_accessor :description
27
23
 
28
- def options=(opts)
29
- @options = []
30
- opts.each do |opt|
31
- @options << DNSimple::ExtendedAttribute::Option.new(opt)
24
+ # Boolean indicating if the extended attribute is required
25
+ attr_accessor :required
26
+
27
+ # An array of options for the extended attribute
28
+ def options
29
+ @options ||= []
32
30
  end
33
- end
34
31
 
35
- # Find the extended attributes for the given TLD
36
- def self.find(tld, options={})
37
- response = DNSimple::Client.get "extended_attributes/#{tld}.json", options
32
+ def options=(opts)
33
+ @options = []
34
+ opts.each do |opt|
35
+ @options << DNSimple::ExtendedAttribute::Option.new(opt)
36
+ end
37
+ end
38
38
 
39
- case response.code
40
- when 200
41
- response.map { |r| new(r) }
42
- else
43
- raise RuntimeError, "Error: #{response.code}"
39
+ # Find the extended attributes for the given TLD
40
+ def self.find(tld, options={})
41
+ response = DNSimple::Client.get("extended_attributes/#{tld}", options)
42
+
43
+ case response.code
44
+ when 200
45
+ response.map { |r| new(r) }
46
+ else
47
+ raise RequestError.new("Error finding extended attributes", response)
48
+ end
44
49
  end
50
+
45
51
  end
46
52
  end
@@ -1,95 +1,99 @@
1
- class DNSimple::Record < DNSimple::Base
2
- Aliases = {
3
- 'priority' => 'prio',
4
- 'time-to-live' => 'ttl'
5
- }
1
+ module DNSimple
6
2
 
7
- attr_accessor :id
3
+ class Record < Base
4
+ Aliases = {
5
+ 'priority' => 'prio',
6
+ 'time-to-live' => 'ttl'
7
+ }
8
8
 
9
- attr_accessor :domain
9
+ attr_accessor :id
10
10
 
11
- attr_accessor :name
11
+ attr_accessor :domain
12
12
 
13
- attr_accessor :content
13
+ attr_accessor :name
14
14
 
15
- attr_accessor :record_type
15
+ attr_accessor :content
16
16
 
17
- attr_accessor :ttl
17
+ attr_accessor :record_type
18
18
 
19
- attr_accessor :prio
19
+ attr_accessor :ttl
20
20
 
21
- def fqdn
22
- [name, domain.name].delete_if { |v| v !~ DNSimple::BLANK_REGEX }.join(".")
23
- end
21
+ attr_accessor :prio
24
22
 
25
- def save(options={})
26
- record_hash = {}
27
- %w(name content ttl prio).each do |attribute|
28
- record_hash[DNSimple::Record.resolve(attribute)] = self.send(attribute)
23
+ def fqdn
24
+ [name, domain.name].delete_if { |v| v !~ DNSimple::BLANK_REGEX }.join(".")
29
25
  end
30
26
 
31
- options.merge!(:body => {:record => record_hash})
27
+ def save(options={})
28
+ record_hash = {}
29
+ %w(name content ttl prio).each do |attribute|
30
+ record_hash[DNSimple::Record.resolve(attribute)] = self.send(attribute)
31
+ end
32
+
33
+ options.merge!(:body => {:record => record_hash})
32
34
 
33
- response = DNSimple::Client.put("domains/#{domain.id}/records/#{id}.json", options)
35
+ response = DNSimple::Client.put("domains/#{domain.id}/records/#{id}", options)
34
36
 
35
- case response.code
36
- when 200
37
- return self
38
- else
39
- raise DNSimple::Error, "Failed to update record: #{response.inspect}"
37
+ case response.code
38
+ when 200
39
+ self
40
+ else
41
+ raise RequestError.new("Error updating record", response)
42
+ end
40
43
  end
41
- end
42
44
 
43
- def delete(options={})
44
- DNSimple::Client.delete "domains/#{domain.id}/records/#{id}", options
45
- end
46
- alias :destroy :delete
45
+ def delete(options={})
46
+ DNSimple::Client.delete("domains/#{domain.id}/records/#{id}", options)
47
+ end
48
+ alias :destroy :delete
47
49
 
48
- def self.resolve(name)
49
- DNSimple::Record::Aliases[name] || name
50
- end
50
+ def self.resolve(name)
51
+ DNSimple::Record::Aliases[name] || name
52
+ end
51
53
 
52
- def self.create(domain, name, record_type, content, options={})
53
- record_hash = {:name => name, :record_type => record_type, :content => content}
54
- record_hash[:ttl] = options.delete(:ttl) || 3600
55
- record_hash[:prio] = options.delete(:priority)
56
- record_hash[:prio] = options.delete(:prio) || ''
54
+ def self.create(domain, name, record_type, content, options={})
55
+ record_hash = {:name => name, :record_type => record_type, :content => content}
56
+ record_hash[:ttl] = options.delete(:ttl) || 3600
57
+ record_hash[:prio] = options.delete(:priority)
58
+ record_hash[:prio] = options.delete(:prio) || ''
57
59
 
58
- options.merge!({:body => {:record => record_hash}})
60
+ options.merge!({:body => {:record => record_hash}})
59
61
 
60
- response = DNSimple::Client.post "domains/#{domain.name}/records", options
62
+ response = DNSimple::Client.post("domains/#{domain.name}/records", options)
61
63
 
62
- case response.code
63
- when 201
64
- return new({:domain => domain}.merge(response["record"]))
65
- when 406
66
- raise DNSimple::RecordExists.new("#{name}.#{domain.name}", response["errors"])
67
- else
68
- raise DNSimple::Error, "Failed to create #{name}.#{domain.name}: #{response["errors"]}"
64
+ case response.code
65
+ when 201
66
+ new({:domain => domain}.merge(response["record"]))
67
+ when 406
68
+ raise RecordExists, "Record #{name}.#{domain.name} already exists"
69
+ else
70
+ raise RequestError.new("Error creating record", response)
71
+ end
69
72
  end
70
- end
71
-
72
- def self.find(domain, id, options={})
73
- response = DNSimple::Client.get("domains/#{domain.name}/records/#{id}", options)
74
73
 
75
- case response.code
76
- when 200
77
- return new({:domain => domain}.merge(response["record"]))
78
- when 404
79
- raise DNSimple::RecordNotFound, "Could not find record #{id} for domain #{domain.name}"
80
- else
81
- raise DNSimple::Error, "Failed to find domain #{domain.name}/#{id}: #{response["errors"]}"
74
+ def self.find(domain, id, options={})
75
+ response = DNSimple::Client.get("domains/#{domain.name}/records/#{id}", options)
76
+
77
+ case response.code
78
+ when 200
79
+ new({:domain => domain}.merge(response["record"]))
80
+ when 404
81
+ raise RecordNotFound, "Could not find record #{id} for domain #{domain.name}"
82
+ else
83
+ raise RequestError.new("Error finding record", response)
84
+ end
82
85
  end
83
- end
84
86
 
85
- def self.all(domain, options={})
86
- response = DNSimple::Client.get("domains/#{domain.name}/records", options)
87
+ def self.all(domain, options={})
88
+ response = DNSimple::Client.get("domains/#{domain.name}/records", options)
87
89
 
88
- case response.code
89
- when 200
90
- response.map { |r| new({:domain => domain}.merge(r["record"])) }
91
- else
92
- raise DNSimple::Error, "Error listing domains: #{response.code}"
90
+ case response.code
91
+ when 200
92
+ response.map { |r| new({:domain => domain}.merge(r["record"])) }
93
+ else
94
+ raise RequestError.new("Error listing records", response)
95
+ end
93
96
  end
97
+
94
98
  end
95
99
  end
@@ -1,35 +1,42 @@
1
- class DNSimple::Service < DNSimple::Base # Class representing a service that can be applied to a domain
2
- attr_accessor :id
1
+ module DNSimple
3
2
 
4
- attr_accessor :name
3
+ # Represents a service that can be applied to a domain.
4
+ class Service < Base
5
5
 
6
- attr_accessor :short_name
6
+ attr_accessor :id
7
7
 
8
- attr_accessor :description
8
+ attr_accessor :name
9
9
 
10
- # Find a service by its ID or short name
11
- def self.find(id_or_short_name, options={})
12
- response = DNSimple::Client.get("services/#{id_or_short_name}.json", options)
10
+ attr_accessor :short_name
13
11
 
14
- case response.code
15
- when 200
16
- return new(response["service"])
17
- when 404
18
- raise RuntimeError, "Could not find service #{id_or_short_name}"
19
- else
20
- raise DNSimple::Error.new(id_or_short_name, response["errors"])
12
+ attr_accessor :description
13
+
14
+ # Find a service by its ID or short name
15
+ def self.find(id_or_short_name, options={})
16
+ id = id_or_short_name
17
+ response = DNSimple::Client.get("services/#{id}", options)
18
+
19
+ case response.code
20
+ when 200
21
+ new(response["service"])
22
+ when 404
23
+ raise RecordNotFound, "Could not find service #{id}"
24
+ else
25
+ raise RequestError.new("Error finding service", response)
26
+ end
21
27
  end
22
- end
23
28
 
24
- # Get all of the services that can be applied to a domain
25
- def self.all(options={})
26
- response = DNSimple::Client.get 'services.json', options
29
+ # Get all of the services that can be applied to a domain
30
+ def self.all(options={})
31
+ response = DNSimple::Client.get("services", options)
27
32
 
28
- case response.code
29
- when 200
30
- response.map { |r| new(r["service"]) }
31
- else
32
- raise RuntimeError, "Error: #{response.code}"
33
+ case response.code
34
+ when 200
35
+ response.map { |r| new(r["service"]) }
36
+ else
37
+ raise RequestError.new("Error listing services", response)
38
+ end
33
39
  end
40
+
34
41
  end
35
42
  end
@@ -1,63 +1,69 @@
1
- class DNSimple::Template < DNSimple::Base
2
- # The template ID in DNSimple
3
- attr_accessor :id
1
+ module DNSimple
4
2
 
5
- # The template name
6
- attr_accessor :name
3
+ class Template < Base
7
4
 
8
- # The template short name
9
- attr_accessor :short_name
5
+ # The template ID in DNSimple
6
+ attr_accessor :id
10
7
 
11
- # The template description
12
- attr_accessor :description
8
+ # The template name
9
+ attr_accessor :name
13
10
 
14
- # Delete the template from DNSimple. WARNING: this cannot
15
- # be undone.
16
- def delete(options={})
17
- DNSimple::Client.delete "templates/#{id}", options
18
- end
19
- alias :destroy :delete
11
+ # The template short name
12
+ attr_accessor :short_name
13
+
14
+ # The template description
15
+ attr_accessor :description
16
+
17
+ # Delete the template from DNSimple. WARNING: this cannot
18
+ # be undone.
19
+ def delete(options={})
20
+ DNSimple::Client.delete("templates/#{id}", options)
21
+ end
22
+ alias :destroy :delete
20
23
 
21
- def self.create(name, short_name, description=nil, options={})
22
- template_hash = {
23
- :name => name,
24
- :short_name => short_name,
25
- :description => description
26
- }
24
+ def self.create(name, short_name, description=nil, options={})
25
+ template_hash = {
26
+ :name => name,
27
+ :short_name => short_name,
28
+ :description => description
29
+ }
27
30
 
28
- options.merge!(:body => {:dns_template => template_hash})
31
+ options.merge!(:body => {:dns_template => template_hash})
29
32
 
30
- response = DNSimple::Client.post 'templates', options
33
+ response = DNSimple::Client.post("templates", options)
31
34
 
32
- case response.code
33
- when 201
34
- return new(response["dns_template"])
35
- else
36
- raise DNSimple::Error.new(name, response["errors"])
35
+ case response.code
36
+ when 201
37
+ new(response["dns_template"])
38
+ else
39
+ raise RequestError.new("Error creating template", response)
40
+ end
37
41
  end
38
- end
39
42
 
40
- def self.find(id_or_short_name, options={})
41
- response = DNSimple::Client.get "templates/#{id_or_short_name}", options
43
+ def self.find(id_or_short_name, options={})
44
+ id = id_or_short_name
45
+ response = DNSimple::Client.get("templates/#{id}", options)
42
46
 
43
- case response.code
44
- when 200
45
- return new(response["dns_template"])
46
- when 404
47
- raise RuntimeError, "Could not find template #{id_or_short_name}"
48
- else
49
- raise DNSimple::Error.new(id_or_short_name, response["errors"])
47
+ case response.code
48
+ when 200
49
+ new(response["dns_template"])
50
+ when 404
51
+ raise RecordNotFound, "Could not find template #{id}"
52
+ else
53
+ raise RequestError.new("Error finding template", response)
54
+ end
50
55
  end
51
- end
52
56
 
53
- def self.all(options={})
54
- response = DNSimple::Client.get 'templates', options
57
+ def self.all(options={})
58
+ response = DNSimple::Client.get("templates", options)
55
59
 
56
- case response.code
57
- when 200
58
- response.map { |r| new(r["dns_template"]) }
59
- else
60
- raise RuntimeError, "Error: #{response.code}"
60
+ case response.code
61
+ when 200
62
+ response.map { |r| new(r["dns_template"]) }
63
+ else
64
+ raise RequestError.new("Error listing templates", response)
65
+ end
61
66
  end
67
+
62
68
  end
63
69
  end