veye 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +15 -0
  2. data/Gemfile +2 -0
  3. data/Gemfile.lock +51 -0
  4. data/README.md +271 -0
  5. data/README.rdoc +6 -0
  6. data/Rakefile +44 -0
  7. data/bin/veye +390 -0
  8. data/lib/veye/api/base_resource.rb +29 -0
  9. data/lib/veye/api/json_response.rb +56 -0
  10. data/lib/veye/api/resource.rb +22 -0
  11. data/lib/veye/api.rb +3 -0
  12. data/lib/veye/package/follow.rb +50 -0
  13. data/lib/veye/package/info.rb +50 -0
  14. data/lib/veye/package/info_csv.rb +18 -0
  15. data/lib/veye/package/info_json.rb +14 -0
  16. data/lib/veye/package/info_pretty.rb +27 -0
  17. data/lib/veye/package/info_table.rb +29 -0
  18. data/lib/veye/package/search.rb +46 -0
  19. data/lib/veye/package/search_csv.rb +33 -0
  20. data/lib/veye/package/search_json.rb +19 -0
  21. data/lib/veye/package/search_pretty.rb +35 -0
  22. data/lib/veye/package/search_table.rb +40 -0
  23. data/lib/veye/package.rb +23 -0
  24. data/lib/veye/pagination/pagination_csv.rb +17 -0
  25. data/lib/veye/pagination/pagination_json.rb +12 -0
  26. data/lib/veye/pagination/pagination_pretty.rb +22 -0
  27. data/lib/veye/pagination/pagination_table.rb +22 -0
  28. data/lib/veye/pagination/show.rb +26 -0
  29. data/lib/veye/pagination.rb +7 -0
  30. data/lib/veye/project/check.rb +147 -0
  31. data/lib/veye/project/licence.rb +48 -0
  32. data/lib/veye/project/project_csv.rb +28 -0
  33. data/lib/veye/project/project_dependency_csv.rb +25 -0
  34. data/lib/veye/project/project_dependency_json.rb +12 -0
  35. data/lib/veye/project/project_dependency_pretty.rb +30 -0
  36. data/lib/veye/project/project_dependency_table.rb +27 -0
  37. data/lib/veye/project/project_json.rb +13 -0
  38. data/lib/veye/project/project_licence_csv.rb +19 -0
  39. data/lib/veye/project/project_licence_json.rb +12 -0
  40. data/lib/veye/project/project_licence_pretty.rb +23 -0
  41. data/lib/veye/project/project_licence_table.rb +29 -0
  42. data/lib/veye/project/project_pretty.rb +28 -0
  43. data/lib/veye/project/project_table.rb +30 -0
  44. data/lib/veye/project.rb +11 -0
  45. data/lib/veye/service.rb +14 -0
  46. data/lib/veye/user/favorite_csv.rb +28 -0
  47. data/lib/veye/user/favorite_json.rb +14 -0
  48. data/lib/veye/user/favorite_pretty.rb +25 -0
  49. data/lib/veye/user/favorite_table.rb +28 -0
  50. data/lib/veye/user/me.rb +75 -0
  51. data/lib/veye/user/profile_csv.rb +21 -0
  52. data/lib/veye/user/profile_json.rb +14 -0
  53. data/lib/veye/user/profile_pretty.rb +31 -0
  54. data/lib/veye/user/profile_table.rb +34 -0
  55. data/lib/veye/user.rb +7 -0
  56. data/lib/veye/version.rb +13 -0
  57. data/lib/veye.rb +82 -0
  58. data/test/default_test.rb +14 -0
  59. data/test/files/Gemfile +20 -0
  60. data/test/files/maven-1.0.1.pom +128 -0
  61. data/test/test_helper.rb +9 -0
  62. data/veye.rdoc +5 -0
  63. metadata +229 -0
@@ -0,0 +1,46 @@
1
+ require_relative 'search_csv.rb'
2
+ require_relative 'search_json.rb'
3
+ require_relative 'search_pretty.rb'
4
+ require_relative 'search_table.rb'
5
+
6
+ module Veye
7
+ module Package
8
+
9
+ class Search
10
+ @@output_formats = {
11
+ 'csv' => SearchCSV.new,
12
+ 'json' => SearchJSON.new,
13
+ 'pretty' => SearchPretty.new,
14
+ 'table' => SearchTable.new
15
+ }
16
+
17
+ def self.search(search_term, language = nil, group_id = nil, page = nil)
18
+ search_api = Veye::API::Resource.new "#{RESOURCE_PATH}/search"
19
+
20
+ search_response = nil
21
+ search_params = {:q => search_term.to_s}
22
+
23
+ search_params[:lang] = Package.encode_language(language) unless language.nil?
24
+ search_params[:g] = group_id unless group_id.nil?
25
+ search_params[:page] = page unless page.nil?
26
+
27
+ request_params = {:params => search_params}
28
+ search_api.resource["/#{search_term}"].get(request_params) do |response, request, result, &block|
29
+ search_response = API::JSONResponse.new(request, result, response)
30
+ end
31
+
32
+ return search_response
33
+ end
34
+
35
+ def self.format(search_results, format = 'pretty', paging = nil)
36
+
37
+ formatter = @@output_formats[format]
38
+ formatter.before
39
+ formatter.format(search_results)
40
+ formatter.after paging
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,33 @@
1
+ module Veye
2
+ module Package
3
+ class SearchCSV
4
+ def before
5
+ printf("nr,name,version,prod_key,version,language,group_id\n")
6
+ end
7
+ def after(paging = nil)
8
+ return if paging.nil?
9
+
10
+ printf("# ------------------------------------------\n")
11
+ printf("current_page,per_page,total_pages,total_entries\n")
12
+ printf("%s,%s,%s,%s\n",
13
+ paging['current_page'],
14
+ paging['per_page'],
15
+ paging['total_pages'],
16
+ paging['total_entries'])
17
+ end
18
+
19
+ def format(results)
20
+ results.each_with_index do |result, index|
21
+ printf("%d,%s,%s,%s,%s,%s,%s\n",
22
+ index + 1,
23
+ result["name"],
24
+ result["version"],
25
+ result["prod_key"],
26
+ result["version"],
27
+ result["language"],
28
+ result["group_id"])
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,19 @@
1
+ module Veye
2
+ module Package
3
+ class SearchJSON
4
+ def before
5
+ @results = {:results => []}
6
+ end
7
+ def after(paging = nil)
8
+ @results[:paging] = paging unless paging.nil?
9
+ printf("%s\n", @results.to_json)
10
+ end
11
+
12
+ def format(results)
13
+ results.each do |result|
14
+ @results[:results] << result
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,35 @@
1
+ require 'rainbow'
2
+
3
+ module Veye
4
+ module Package
5
+ class SearchPretty
6
+ def before; end
7
+ def after(paging = nil)
8
+ return if paging.nil?
9
+
10
+ printf("\n#-- %s\n", "Pagination information".bright)
11
+ printf("\t%-15s: %s\n", "Current page", paging['current_page'])
12
+ printf("\t%-15s: %s\n", "Per page", paging['per_page'])
13
+ printf("\t%-15s: %s\n", "Total pages", paging['total_pages'])
14
+ printf("\t%-15s: %s\n", "Total entries", paging['total_entries'])
15
+
16
+ end
17
+
18
+ def format(results)
19
+ results.each_with_index do |result, index|
20
+ printf("%3d - %s\n",
21
+ index + 1,
22
+ "#{result["name"]}".foreground(:green).bright)
23
+ printf("\t%-15s: %s\n", "Product key", result["prod_key"])
24
+ printf("\t%-15s: %s\n", "Latest version",
25
+ "#{result["version"]}".bright)
26
+ printf("\t%-15s: %s\n", "Language", result["language"])
27
+
28
+ if result.has_key? "group_id" and not result["group_id"].empty?
29
+ printf("\t%-15s: %s\n", "Group id", result["group_id"])
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,40 @@
1
+ require 'terminal-table'
2
+
3
+ module Veye
4
+ module Package
5
+ class SearchTable
6
+ def before
7
+ @@table = Terminal::Table.new :title => "Package search",
8
+ :headings => %w(index name version product_key language group_id)
9
+ @@table.align_column(0, :right)
10
+ end
11
+
12
+ def after(paging = nil)
13
+ unless paging.nil?
14
+ paging_header = ['p', 'current_page', 'per_page', 'total_pages', 'total_entries']
15
+ paging_data = ["p"]
16
+ paging.each_pair do |key, val|
17
+ paging_data << val
18
+ end
19
+
20
+ @@table.add_separator
21
+ @@table << paging_header
22
+ @@table << paging_data
23
+ end
24
+
25
+ puts @@table.to_s
26
+ end
27
+
28
+ def format(results)
29
+ results.each_with_index do |result, index|
30
+ row = [index+1, result["name"], result["version"], result["prod_key"]]
31
+ row << result["language"]
32
+ row << result["group_id"]
33
+
34
+ @@table << row
35
+ end
36
+ end
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,23 @@
1
+ require_relative 'package/info.rb'
2
+ require_relative 'package/search.rb'
3
+ require_relative 'package/follow.rb'
4
+
5
+ # -- define module constants here
6
+ module Veye
7
+ module Package
8
+ RESOURCE_PATH = "/products"
9
+
10
+ def supported_languages
11
+ Set.new ["Clojure", "Java", "Javascript", "Node.JS", "PHP", "Python", "Ruby", "R"]
12
+ end
13
+
14
+ def self.encode_prod_key(prod_key)
15
+ prod_key = prod_key.to_s
16
+ prod_key.gsub(/\//, ":").gsub(/\./, "~")
17
+ end
18
+
19
+ def self.encode_language(lang)
20
+ lang.gsub(/\./, "").downcase
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,17 @@
1
+ module Veye
2
+ module Pagination
3
+ class PaginationCSV
4
+ def before
5
+ printf("current_page,per_page,total_pages,total_entries\n")
6
+ end
7
+
8
+ def after; end
9
+
10
+ def format(paging)
11
+ printf("%s,%s,%s,%s\n",
12
+ paging['current_page'], paging['per_page'],
13
+ paging['total_pages'], paging['total_entries'])
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ module Veye
2
+ module Pagination
3
+ class PaginationJSON
4
+ def before; end
5
+ def after; end
6
+
7
+ def format(paging)
8
+ printf("%s\n", {'paging' => paging}.to_json)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,22 @@
1
+ require 'rainbow'
2
+
3
+ module Veye
4
+ module Pagination
5
+ class PaginationPretty
6
+ def before; end
7
+ def after; end
8
+
9
+ def format(paging)
10
+ printf("\t%15s - %s\n",
11
+ "Current page".foreground(:green).bright,
12
+ "#{paging['current_page']}".bright)
13
+ puts "\t-------------------------"
14
+ printf("\t%-15s: %s\n", "Per page", paging['per_page'])
15
+ printf("\t%-15s: %s\n", "Total pages", paging['total_pages'])
16
+ printf("\t%-15s: %s\n", "Total entries", paging['total_entries'])
17
+
18
+ end
19
+ end
20
+ end
21
+ end
22
+
@@ -0,0 +1,22 @@
1
+ require 'terminal-table'
2
+
3
+ module Veye
4
+ module Pagination
5
+ class PaginationTable
6
+ def before
7
+ @@table = Terminal::Table.new :title => "Pagination",
8
+ :headings => %w(current_page per_page total_pages total_entries)
9
+ @@table.align_column(0, :right)
10
+ end
11
+
12
+ def after
13
+ puts @@table.to_s
14
+ end
15
+
16
+ def format(paging)
17
+ row = [paging['current_page'], paging['per_page'], paging['total_pages'], paging['total_entries']]
18
+ @@table << row
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,26 @@
1
+ require_relative 'pagination_csv.rb'
2
+ require_relative 'pagination_json.rb'
3
+ require_relative 'pagination_pretty.rb'
4
+ require_relative 'pagination_table.rb'
5
+
6
+ module Veye
7
+ module Pagination
8
+ class Show
9
+ @@pagination_formats = {
10
+ 'csv' => PaginationCSV.new,
11
+ 'json' => PaginationJSON.new,
12
+ 'pretty' => PaginationPretty.new,
13
+ 'table' => PaginationTable.new
14
+ }
15
+
16
+ def self.format(paging, format = 'pretty')
17
+ formatter = @@pagination_formats[format]
18
+
19
+ formatter.before
20
+ formatter.format paging
21
+ formatter.after
22
+ end
23
+ end
24
+ end
25
+ end
26
+
@@ -0,0 +1,7 @@
1
+ require_relative 'pagination/show.rb'
2
+
3
+ module Veye
4
+ module Pagination
5
+ #add module constants here
6
+ end
7
+ end
@@ -0,0 +1,147 @@
1
+ require 'json'
2
+
3
+ require_relative 'project_csv.rb'
4
+ require_relative 'project_json.rb'
5
+ require_relative 'project_pretty.rb'
6
+ require_relative 'project_table.rb'
7
+
8
+ require_relative 'project_dependency_csv.rb'
9
+ require_relative 'project_dependency_json.rb'
10
+ require_relative 'project_dependency_pretty.rb'
11
+ require_relative 'project_dependency_table.rb'
12
+
13
+ module Veye
14
+ module Project
15
+ class Check
16
+ @@output_formats = {
17
+ "csv" => ProjectCSV.new,
18
+ "json" => ProjectJSON.new,
19
+ "pretty" => ProjectPretty.new,
20
+ "table" => ProjectTable.new
21
+ }
22
+
23
+ @@dependency_output_formats = {
24
+ "csv" => ProjectDependencyCSV.new,
25
+ "json" => ProjectDependencyJSON.new,
26
+ "pretty" => ProjectDependencyPretty.new,
27
+ "table" => ProjectDependencyTable.new
28
+ }
29
+
30
+
31
+ def self.get_list(api_key)
32
+ project_api = API::Resource.new(RESOURCE_PATH)
33
+ qparams = {:params => {:api_key => api_key}}
34
+
35
+ project_api.resource.get(qparams) do |response, request, result|
36
+ response_data = API::JSONResponse.new(request, result, response)
37
+ end
38
+ end
39
+
40
+ def self.upload(filename, api_key)
41
+ response_data = {:success => false}
42
+ file_path = File.absolute_path(filename)
43
+
44
+ unless File.exists?(file_path)
45
+ error_msg = sprintf("%s: Cant read file `%s`",
46
+ "Error".foreground(:red),
47
+ "#{filename}".foreground(:yellow)
48
+ )
49
+ exit_now!(error_msg)
50
+ end
51
+
52
+ file_size = File.size(file_path)
53
+ unless file_size != 0 and file_size < MAX_FILE_SIZE
54
+ exit_now!("Size of file is not acceptable: 0kb < x <= #{MAX_FILE_SIZE/1000}kb")
55
+ end
56
+
57
+ project_api = API::Resource.new(RESOURCE_PATH)
58
+ file_obj = File.open(file_path, 'rb')
59
+
60
+ upload_data = {
61
+ :upload => file_obj,
62
+ :api_key => api_key
63
+ }
64
+ project_api.resource.post(upload_data) do |response, request, result, &block|
65
+ response_data = API::JSONResponse.new(request, result, response)
66
+ end
67
+
68
+ return response_data
69
+ end
70
+
71
+ def self.update(project_key, filename, api_key)
72
+ response_data = {:success => false}
73
+ file_path = File.absolute_path(filename)
74
+
75
+ unless File.exists?(file_path)
76
+ error_msg = sprintf("%s: Cant read file `%s`",
77
+ "Error".foreground(:red),
78
+ "#{filename}".foreground(:yellow)
79
+ )
80
+ exit_now!(error_msg)
81
+ end
82
+
83
+ file_size = File.size(file_path)
84
+ unless file_size != 0 and file_size < MAX_FILE_SIZE
85
+ exit_now!(" The size of file is not acceptable: 0kb < x <= #{MAX_FILE_SIZE/1000}kb")
86
+ end
87
+
88
+ project_api = API::Resource.new("#{RESOURCE_PATH}/#{project_key}")
89
+ file_obj = File.open(file_path, 'rb')
90
+ upload_data = {
91
+ :project_file => file_obj,
92
+ :api_key => api_key
93
+ }
94
+ project_api.resource.post(upload_data) do |response, request, result, &block|
95
+ response_data = API::JSONResponse.new(request, result, response)
96
+ end
97
+ end
98
+ def self.get_project(project_key, api_key)
99
+ response_data = nil
100
+ project_api = API::Resource.new(RESOURCE_PATH)
101
+
102
+ if project_key.nil? or project_key.empty?
103
+ error_msg = sprintf("%s: %s",
104
+ "Error".foreground(:red),
105
+ "Not valid project_key: `#{project_key}`")
106
+ exit_now! error_msg
107
+ end
108
+
109
+ project_url = "/#{project_key}"
110
+ qparams = {:params => {:api_key => api_key}}
111
+ project_api.resource[project_url].get(qparams) do |response, request, result|
112
+ response_data = API::JSONResponse.new(request, result, response)
113
+ end
114
+
115
+ return response_data
116
+ end
117
+
118
+ def self.delete_project(project_key, api_key)
119
+ project_api = Veye::API::Resource.new(RESOURCE_PATH)
120
+ qparams = {:params => {:api_key => api_key}}
121
+ response_data = nil
122
+
123
+ project_api.resource["/#{project_key}"].delete(qparams) do |response, request, result|
124
+ response_data = API::JSONResponse.new(request, result, response)
125
+ end
126
+
127
+ return response_data
128
+ end
129
+
130
+ def self.format(results, format = 'pretty')
131
+ formatter = @@output_formats[format]
132
+ formatter.before
133
+ formatter.format results
134
+ formatter.after
135
+ end
136
+
137
+ def self.format_dependencies(results, format = 'pretty')
138
+ formatter = @@dependency_output_formats[format]
139
+ formatter.before
140
+ formatter.format results
141
+ formatter.after
142
+ end
143
+
144
+ end
145
+ end
146
+ end
147
+
@@ -0,0 +1,48 @@
1
+ require 'json'
2
+
3
+ require_relative 'project_licence_csv.rb'
4
+ require_relative 'project_licence_json.rb'
5
+ require_relative 'project_licence_pretty.rb'
6
+ require_relative 'project_licence_table.rb'
7
+
8
+ module Veye
9
+ module Project
10
+ class Licence
11
+ @@output_formats = {
12
+ "csv" => ProjectLicenceCSV.new,
13
+ "json" => ProjectLicenceJSON.new,
14
+ "pretty" => ProjectLicencePretty.new,
15
+ "table" => ProjectLicenceTable.new
16
+ }
17
+
18
+ def self.get_project(project_key, api_key)
19
+ response_data = nil
20
+ project_api = API::Resource.new(RESOURCE_PATH)
21
+
22
+ if project_key.nil? or project_key.empty?
23
+ error_msg = sprintf("%s: %s",
24
+ "Error".foreground(:red),
25
+ "Not valid project_key: `#{project_key}`")
26
+ exit_now! error_msg
27
+ end
28
+
29
+ project_url = "/#{project_key}/licenses"
30
+ qparams = {:params => {:api_key => api_key}}
31
+ project_api.resource[project_url].get(qparams) do |response, request, result|
32
+ response_data = API::JSONResponse.new(request, result, response)
33
+ end
34
+
35
+ return response_data
36
+ end
37
+
38
+ def self.format(results, format = 'pretty')
39
+ formatter = @@output_formats[format]
40
+ formatter.before
41
+ formatter.format results
42
+ formatter.after
43
+ end
44
+
45
+ end
46
+ end
47
+ end
48
+
@@ -0,0 +1,28 @@
1
+ module Veye
2
+ module Project
3
+ class ProjectCSV
4
+ def before
5
+ printf("nr,name,project_key,private,period,source,dep_number,out_number,created_at\n")
6
+ end
7
+ def after; end
8
+
9
+ def format(results)
10
+ results = [results] if results.is_a? Hash
11
+
12
+ results.each_with_index do |result, index|
13
+ printf("%d,%s,%s,%s,%s,%s,%s,%s,%s\n",
14
+ index + 1,
15
+ result['name'],
16
+ result['project_key'],
17
+ result['private'],
18
+ result['period'],
19
+ result['source'],
20
+ result['dep_number'],
21
+ result['out_number'],
22
+ result['created_at'])
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+
@@ -0,0 +1,25 @@
1
+ module Veye
2
+ module Project
3
+ class ProjectDependencyCSV
4
+ def before
5
+ printf("nr,name,prod_key,outdated,latest,current\n",nil)
6
+ end
7
+ def after; end
8
+
9
+ def format(results)
10
+ results = [results] if results.is_a?(Hash)
11
+
12
+ results.each_with_index do |result, index|
13
+ printf("%d,%s,%s,%s,%s,%s\n",
14
+ index + 1,
15
+ result["name"],
16
+ result["prod_key"],
17
+ result["outdated"],
18
+ result["version_current"],
19
+ result["version_requested"],
20
+ )
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,12 @@
1
+ module Veye
2
+ module Project
3
+ class ProjectDependencyJSON
4
+ def before; end
5
+ def after; end
6
+
7
+ def format(results)
8
+ printf("%s\n", {"dependencies" => results}.to_json)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,30 @@
1
+ require 'rainbow'
2
+
3
+ module Veye
4
+ module Project
5
+ class ProjectDependencyPretty
6
+ def before; end
7
+ def after; end
8
+
9
+ def format(results)
10
+ results = [results] if results.is_a?(Hash)
11
+ results.each_with_index do |result, index|
12
+ project_name = "#{result['name']}".foreground(:green).bright
13
+ printf("%3d - %s\n", index + 1, project_name)
14
+ printf("\t%-15s: %s\n", "Product key", result["prod_key"])
15
+
16
+ color = (result["outdated"] == true) ? :red : :green
17
+ printf("\t%-15s: %s\n", "Outdated",
18
+ "#{result['outdated']}".foreground(color))
19
+
20
+ printf("\t%-15s: %s\n", "Latest version",
21
+ "#{result['version_current']}".foreground(color))
22
+
23
+ printf("\t%-15s: %s\n", "Current version", result["version_requested"])
24
+
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+
@@ -0,0 +1,27 @@
1
+ require 'terminal-table'
2
+
3
+ module Veye
4
+ module Project
5
+ class ProjectDependencyTable
6
+ def before
7
+ @@table = Terminal::Table.new :title => "Version check",
8
+ :headings => %w(index name prod_key version_current version_latest)
9
+ @@table.align_column(0, :right)
10
+ end
11
+
12
+ def after
13
+ puts @@table.to_s
14
+ end
15
+
16
+ def format(results)
17
+ results = [results] if results.is_a?(Hash)
18
+
19
+ results.each_with_index do |result, index|
20
+ row = [index + 1, result["name"], result["prod_key"],
21
+ result["version_current"], result["version_requested"]]
22
+ @@table << row
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,13 @@
1
+ module Veye
2
+ module Project
3
+ class ProjectJSON
4
+ def before; end
5
+ def after; end
6
+
7
+ def format(results)
8
+ printf("%s\n", {"projects" => results}.to_json)
9
+ end
10
+ end
11
+ end
12
+ end
13
+
@@ -0,0 +1,19 @@
1
+ module Veye
2
+ module Project
3
+ class ProjectLicenceCSV
4
+ def before
5
+ printf("nr,licence,product keys\n")
6
+ end
7
+ def after; end
8
+
9
+ def format(results)
10
+ n = 1
11
+ results["licenses"].each_pair do |licence, prods|
12
+ prod_keys = prods.map {|p| p["prod_key"]}
13
+ printf("%d,%s,%s\n", n, licence, prod_keys.join(','))
14
+ n += 1
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end