gemstash 2.0.0 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +57 -0
- data/exe/gemstash +3 -0
- data/lib/gemstash/api_key_authorization.rb +3 -0
- data/lib/gemstash/authorization.rb +7 -3
- data/lib/gemstash/cache.rb +42 -2
- data/lib/gemstash/cli/authorize.rb +5 -5
- data/lib/gemstash/cli/base.rb +4 -1
- data/lib/gemstash/cli/setup.rb +19 -4
- data/lib/gemstash/cli/start.rb +4 -1
- data/lib/gemstash/cli/status.rb +2 -0
- data/lib/gemstash/cli/stop.rb +2 -0
- data/lib/gemstash/cli.rb +2 -0
- data/lib/gemstash/config.ru +3 -3
- data/lib/gemstash/configuration.rb +8 -2
- data/lib/gemstash/db/authorization.rb +2 -0
- data/lib/gemstash/db/cached_rubygem.rb +3 -0
- data/lib/gemstash/db/dependency.rb +2 -0
- data/lib/gemstash/db/rubygem.rb +3 -0
- data/lib/gemstash/db/upstream.rb +3 -0
- data/lib/gemstash/db/version.rb +3 -0
- data/lib/gemstash/db.rb +3 -0
- data/lib/gemstash/dependencies.rb +6 -2
- data/lib/gemstash/env.rb +24 -4
- data/lib/gemstash/gem_fetcher.rb +4 -2
- data/lib/gemstash/gem_pusher.rb +7 -5
- data/lib/gemstash/gem_source/dependency_caching.rb +4 -4
- data/lib/gemstash/gem_source/private_source.rb +6 -3
- data/lib/gemstash/gem_source/rack_middleware.rb +3 -0
- data/lib/gemstash/gem_source/upstream_source.rb +9 -3
- data/lib/gemstash/gem_source.rb +4 -2
- data/lib/gemstash/gem_yanker.rb +4 -0
- data/lib/gemstash/health.rb +2 -0
- data/lib/gemstash/http_client.rb +12 -4
- data/lib/gemstash/logging.rb +3 -1
- data/lib/gemstash/man/gemstash-authorize.1.txt +0 -65
- data/lib/gemstash/man/gemstash-configuration.5.txt +0 -65
- data/lib/gemstash/man/gemstash-customize.7.txt +0 -65
- data/lib/gemstash/man/gemstash-debugging.7.txt +0 -65
- data/lib/gemstash/man/gemstash-deploy.7.txt +0 -65
- data/lib/gemstash/man/gemstash-mirror.7.txt +0 -65
- data/lib/gemstash/man/gemstash-multiple-sources.7.txt +0 -65
- data/lib/gemstash/man/gemstash-private-gems.7.txt +0 -65
- data/lib/gemstash/man/gemstash-readme.7.txt +0 -65
- data/lib/gemstash/man/gemstash-setup.1.txt +0 -65
- data/lib/gemstash/man/gemstash-start.1.txt +0 -65
- data/lib/gemstash/man/gemstash-status.1.txt +0 -65
- data/lib/gemstash/man/gemstash-stop.1.txt +0 -65
- data/lib/gemstash/man/gemstash-version.1.txt +0 -65
- data/lib/gemstash/migrations/01_gem_dependencies.rb +2 -0
- data/lib/gemstash/migrations/02_authorizations.rb +2 -0
- data/lib/gemstash/migrations/03_cached_gems.rb +2 -0
- data/lib/gemstash/migrations/04_health_tests.rb +2 -0
- data/lib/gemstash/puma.rb +2 -0
- data/lib/gemstash/rack_env_rewriter.rb +11 -2
- data/lib/gemstash/specs_builder.rb +5 -1
- data/lib/gemstash/storage.rb +17 -7
- data/lib/gemstash/upstream.rb +8 -5
- data/lib/gemstash/version.rb +4 -2
- data/lib/gemstash/web.rb +8 -4
- data/lib/gemstash.rb +3 -1
- metadata +40 -133
data/lib/gemstash/gem_fetcher.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "gemstash"
|
2
4
|
require "set"
|
3
5
|
|
4
6
|
module Gemstash
|
5
|
-
|
7
|
+
# :nodoc:
|
6
8
|
class GemFetcher
|
7
9
|
def initialize(http_client)
|
8
10
|
@http_client = http_client
|
9
|
-
@valid_headers = Set.new([
|
11
|
+
@valid_headers = Set.new(%w[etag content-type content-length last-modified])
|
10
12
|
end
|
11
13
|
|
12
14
|
def fetch(gem_id, type, &block)
|
data/lib/gemstash/gem_pusher.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "gemstash"
|
2
4
|
require "rubygems/package"
|
3
5
|
require "stringio"
|
4
6
|
|
5
|
-
|
7
|
+
# :nodoc:
|
6
8
|
module Gemstash
|
7
9
|
# Class that supports pushing a new gem to the private repository of gems.
|
8
10
|
class GemPusher
|
@@ -56,9 +58,7 @@ module Gemstash
|
|
56
58
|
resource_exist = storage.resource(full_name).exist?
|
57
59
|
resource_is_indexed = storage.resource(full_name).properties[:indexed] if resource_exist
|
58
60
|
|
59
|
-
if resource_exist && resource_is_indexed
|
60
|
-
raise ExistingVersionError, "Cannot push to an existing version!"
|
61
|
-
end
|
61
|
+
raise ExistingVersionError, "Cannot push to an existing version!" if resource_exist && resource_is_indexed
|
62
62
|
|
63
63
|
storage.resource(full_name).save({ gem: @content }, indexed: true)
|
64
64
|
end
|
@@ -78,6 +78,7 @@ module Gemstash
|
|
78
78
|
existing = Gemstash::DB::Version.find_by_spec(gem_id, spec)
|
79
79
|
raise ExistingVersionError, "Cannot push to an existing version!" if existing && existing.indexed
|
80
80
|
raise YankedVersionError, "Cannot push to a yanked version!" if existing && !existing.indexed
|
81
|
+
|
81
82
|
version_id = Gemstash::DB::Version.insert_by_spec(gem_id, spec)
|
82
83
|
Gemstash::DB::Dependency.insert_by_spec(version_id, spec)
|
83
84
|
end
|
@@ -120,11 +121,12 @@ module Gemstash
|
|
120
121
|
|
121
122
|
def cleanup
|
122
123
|
return unless @tempfile
|
124
|
+
|
123
125
|
@tempfile.close
|
124
126
|
@tempfile.unlink
|
125
127
|
end
|
126
128
|
end
|
127
129
|
|
128
|
-
GemPusher.
|
130
|
+
GemPusher.include LegacyRubyGemsSupport
|
129
131
|
end
|
130
132
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Gemstash
|
2
4
|
module GemSource
|
3
5
|
# Module for caching dependencies in a GemSource.
|
@@ -7,9 +9,7 @@ module Gemstash
|
|
7
9
|
def serve_dependencies
|
8
10
|
gems = gems_from_params
|
9
11
|
|
10
|
-
if gems.length > API_REQUEST_LIMIT
|
11
|
-
halt 422, "Too many gems (use --full-index instead)"
|
12
|
-
end
|
12
|
+
halt 422, "Too many gems (use --full-index instead)" if gems.length > API_REQUEST_LIMIT
|
13
13
|
|
14
14
|
content_type "application/octet-stream"
|
15
15
|
Marshal.dump dependencies.fetch(gems)
|
@@ -21,7 +21,7 @@ module Gemstash
|
|
21
21
|
if gems.length > API_REQUEST_LIMIT
|
22
22
|
halt 422, {
|
23
23
|
"error" => "Too many gems (use --full-index instead)",
|
24
|
-
"code"
|
24
|
+
"code" => 422
|
25
25
|
}.to_json
|
26
26
|
end
|
27
27
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "gemstash"
|
2
4
|
|
3
5
|
module Gemstash
|
@@ -15,6 +17,7 @@ module Gemstash
|
|
15
17
|
def self.matches?(env)
|
16
18
|
rewriter = rack_env_rewriter.for(env)
|
17
19
|
return false unless rewriter.matches?
|
20
|
+
|
18
21
|
rewriter.rewrite
|
19
22
|
true
|
20
23
|
end
|
@@ -44,7 +47,7 @@ module Gemstash
|
|
44
47
|
end
|
45
48
|
|
46
49
|
def serve_versions
|
47
|
-
halt
|
50
|
+
halt 404, "Not yet supported"
|
48
51
|
end
|
49
52
|
|
50
53
|
def serve_info(name)
|
@@ -54,7 +57,7 @@ module Gemstash
|
|
54
57
|
def serve_marshal(id)
|
55
58
|
authorization.protect(self) do
|
56
59
|
auth.check("fetch") if gemstash_env.config[:protected_fetch]
|
57
|
-
gem_full_name = id.
|
60
|
+
gem_full_name = id.delete_suffix(".gemspec.rz")
|
58
61
|
gem = fetch_gem(gem_full_name)
|
59
62
|
halt 404 unless gem.exist?(:spec)
|
60
63
|
content_type "application/octet-stream"
|
@@ -69,7 +72,7 @@ module Gemstash
|
|
69
72
|
def serve_gem(id)
|
70
73
|
authorization.protect(self) do
|
71
74
|
auth.check("fetch") if gemstash_env.config[:protected_fetch]
|
72
|
-
gem_full_name = id.
|
75
|
+
gem_full_name = id.delete_suffix(".gem")
|
73
76
|
gem = fetch_gem(gem_full_name)
|
74
77
|
content_type "application/octet-stream"
|
75
78
|
gem.content(:gem)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "gemstash"
|
2
4
|
|
3
5
|
module Gemstash
|
@@ -11,6 +13,7 @@ module Gemstash
|
|
11
13
|
def call(env)
|
12
14
|
Gemstash::GemSource.sources.each do |source|
|
13
15
|
next unless source.matches?(env)
|
16
|
+
|
14
17
|
env["gemstash.gem_source"] = source
|
15
18
|
break
|
16
19
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "gemstash"
|
2
4
|
require "cgi"
|
3
5
|
|
@@ -12,6 +14,7 @@ module Gemstash
|
|
12
14
|
def self.matches?(env)
|
13
15
|
rewriter = rack_env_rewriter.for(env)
|
14
16
|
return false unless rewriter.matches?
|
17
|
+
|
15
18
|
rewriter.rewrite
|
16
19
|
env["gemstash.upstream"] = rewriter.captures["upstream_url"]
|
17
20
|
capture_user_agent(env)
|
@@ -90,8 +93,10 @@ module Gemstash
|
|
90
93
|
private
|
91
94
|
|
92
95
|
def upstream
|
93
|
-
@upstream ||= Gemstash::Upstream.new(
|
94
|
-
|
96
|
+
@upstream ||= Gemstash::Upstream.new(
|
97
|
+
env["gemstash.upstream"],
|
98
|
+
user_agent: env["gemstash.user-agent"]
|
99
|
+
)
|
95
100
|
end
|
96
101
|
|
97
102
|
def index_upstream
|
@@ -135,6 +140,7 @@ module Gemstash
|
|
135
140
|
|
136
141
|
def set_gem_headers(gem, resource_type)
|
137
142
|
return unless gem.property?(:headers, resource_type)
|
143
|
+
|
138
144
|
gem_headers = gem.properties[:headers][resource_type]
|
139
145
|
headers["Content-Type"] = gem_headers["content-type"] if gem_headers.include?("content-type")
|
140
146
|
headers["Last-Modified"] = gem_headers["last-modified"] if gem_headers.include?("last-modified")
|
@@ -192,7 +198,7 @@ module Gemstash
|
|
192
198
|
# default upstream).
|
193
199
|
class RubygemsSource < Gemstash::GemSource::UpstreamSource
|
194
200
|
def self.matches?(env)
|
195
|
-
env["gemstash.upstream"] = if env["HTTP_X_GEMFILE_SOURCE"].to_s.empty?
|
201
|
+
env["gemstash.upstream"] = if env["gemstash.env"].config[:ignore_gemfile_source] || env["HTTP_X_GEMFILE_SOURCE"].to_s.empty?
|
196
202
|
env["gemstash.env"].config[:rubygems_url]
|
197
203
|
else
|
198
204
|
env["HTTP_X_GEMFILE_SOURCE"]
|
data/lib/gemstash/gem_source.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "gemstash"
|
2
4
|
require "forwardable"
|
3
5
|
|
4
6
|
module Gemstash
|
5
|
-
|
7
|
+
# :nodoc:
|
6
8
|
module GemSource
|
7
9
|
autoload :DependencyCaching, "gemstash/gem_source/dependency_caching"
|
8
10
|
autoload :PrivateSource, "gemstash/gem_source/private_source"
|
@@ -27,7 +29,7 @@ module Gemstash
|
|
27
29
|
include Gemstash::Logging
|
28
30
|
|
29
31
|
def_delegators :@app, :cache_control, :content_type, :env, :halt,
|
30
|
-
|
32
|
+
:headers, :http_client_for, :params, :redirect, :request
|
31
33
|
|
32
34
|
def initialize(app)
|
33
35
|
@app = app
|
data/lib/gemstash/gem_yanker.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "gemstash"
|
2
4
|
|
3
5
|
module Gemstash
|
@@ -52,9 +54,11 @@ module Gemstash
|
|
52
54
|
def update_database
|
53
55
|
gemstash_env.db.transaction do
|
54
56
|
raise UnknownGemError, "Cannot yank an unknown gem!" unless Gemstash::DB::Rubygem[name: @gem_name]
|
57
|
+
|
55
58
|
version = Gemstash::DB::Version.find_by_full_name(full_name)
|
56
59
|
raise UnknownVersionError, "Cannot yank an unknown version!" unless version
|
57
60
|
raise YankedVersionError, "Cannot yank an already yanked version!" unless version.indexed
|
61
|
+
|
58
62
|
version.deindex
|
59
63
|
storage.resource(version.storage_id).update_properties(indexed: false)
|
60
64
|
end
|
data/lib/gemstash/health.rb
CHANGED
data/lib/gemstash/http_client.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "gemstash"
|
2
4
|
require "faraday"
|
3
5
|
require "faraday_middleware"
|
4
6
|
|
5
7
|
module Gemstash
|
6
|
-
|
8
|
+
# :nodoc:
|
7
9
|
class WebError < StandardError
|
8
10
|
attr_reader :code
|
9
11
|
|
@@ -13,19 +15,19 @@ module Gemstash
|
|
13
15
|
end
|
14
16
|
end
|
15
17
|
|
16
|
-
|
18
|
+
# :nodoc:
|
17
19
|
class ConnectionError < WebError
|
18
20
|
def initialize(message)
|
19
21
|
super(message, 502) # Bad Gateway
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
23
|
-
|
25
|
+
# :nodoc:
|
24
26
|
class HTTPClient
|
25
27
|
extend Gemstash::Env::Helper
|
26
28
|
include Gemstash::Logging
|
27
29
|
|
28
|
-
DEFAULT_USER_AGENT = "Gemstash/#{Gemstash::VERSION}"
|
30
|
+
DEFAULT_USER_AGENT = "Gemstash/#{Gemstash::VERSION}"
|
29
31
|
|
30
32
|
def self.for(upstream)
|
31
33
|
client = Faraday.new(upstream.to_s) do |config|
|
@@ -33,12 +35,17 @@ module Gemstash
|
|
33
35
|
config.adapter :net_http
|
34
36
|
config.options.timeout = gemstash_env.config[:fetch_timeout]
|
35
37
|
end
|
38
|
+
|
39
|
+
client.basic_auth(upstream.user, upstream.password) if upstream.auth?
|
40
|
+
|
36
41
|
user_agent = "#{upstream.user_agent} " unless upstream.user_agent.to_s.empty?
|
37
42
|
user_agent = user_agent.to_s + DEFAULT_USER_AGENT
|
38
43
|
|
39
44
|
new(client, user_agent: user_agent)
|
40
45
|
end
|
41
46
|
|
47
|
+
attr_reader :client
|
48
|
+
|
42
49
|
def initialize(client = nil, user_agent: nil)
|
43
50
|
@client = client
|
44
51
|
@user_agent = user_agent || DEFAULT_USER_AGENT
|
@@ -71,6 +78,7 @@ module Gemstash
|
|
71
78
|
rescue Faraday::ConnectionFailed => e
|
72
79
|
log_error("Connection failure", e)
|
73
80
|
raise(ConnectionError, e.message) unless times > 0
|
81
|
+
|
74
82
|
log.info "retrying... #{times} more times"
|
75
83
|
end
|
76
84
|
end
|
data/lib/gemstash/logging.rb
CHANGED
@@ -1,66 +1 @@
|
|
1
1
|
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
@@ -1,66 +1 @@
|
|
1
1
|
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
@@ -1,66 +1 @@
|
|
1
1
|
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
@@ -1,66 +1 @@
|
|
1
1
|
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
@@ -1,66 +1 @@
|
|
1
1
|
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
@@ -1,66 +1 @@
|
|
1
1
|
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|