dependabot-gradle 0.320.0 → 0.321.0
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.
- checksums.yaml +4 -4
- data/lib/dependabot/gradle/file_parser/property_value_finder.rb +28 -19
- data/lib/dependabot/gradle/file_parser/repositories_finder.rb +62 -34
- data/lib/dependabot/gradle/file_parser.rb +197 -65
- data/lib/dependabot/gradle/file_updater/property_value_updater.rb +4 -7
- data/lib/dependabot/gradle/file_updater.rb +1 -1
- data/lib/dependabot/gradle/package/package_details_fetcher.rb +11 -13
- data/lib/dependabot/gradle/update_checker/requirements_updater.rb +2 -2
- data/lib/dependabot/gradle/update_checker/version_finder.rb +1 -1
- data/lib/dependabot/gradle/update_checker.rb +54 -14
- data/lib/dependabot/gradle/version.rb +56 -27
- metadata +6 -6
@@ -1,6 +1,7 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require "sorbet-runtime"
|
4
5
|
require "dependabot/update_checkers"
|
5
6
|
require "dependabot/update_checkers/base"
|
6
7
|
require "dependabot/gradle/file_parser"
|
@@ -8,16 +9,20 @@ require "dependabot/gradle/file_parser"
|
|
8
9
|
module Dependabot
|
9
10
|
module Gradle
|
10
11
|
class UpdateChecker < Dependabot::UpdateCheckers::Base
|
12
|
+
extend T::Sig
|
13
|
+
|
11
14
|
require_relative "update_checker/requirements_updater"
|
12
15
|
require_relative "update_checker/version_finder"
|
13
16
|
require_relative "update_checker/multi_dependency_updater"
|
14
17
|
|
18
|
+
sig { override.returns(T.nilable(Dependabot::Version)) }
|
15
19
|
def latest_version
|
16
20
|
return if git_dependency?
|
17
21
|
|
18
22
|
latest_version_details&.fetch(:version)
|
19
23
|
end
|
20
24
|
|
25
|
+
sig { override.returns(T.nilable(Dependabot::Version)) }
|
21
26
|
def latest_resolvable_version
|
22
27
|
# TODO: Resolve the build.gradle to find the latest version we could
|
23
28
|
# update to without updating any other dependencies at the same time.
|
@@ -31,10 +36,12 @@ module Dependabot
|
|
31
36
|
latest_version
|
32
37
|
end
|
33
38
|
|
39
|
+
sig { override.returns(T.nilable(Dependabot::Version)) }
|
34
40
|
def lowest_security_fix_version
|
35
41
|
lowest_security_fix_version_details&.fetch(:version)
|
36
42
|
end
|
37
43
|
|
44
|
+
sig { override.returns(T.nilable(Dependabot::Version)) }
|
38
45
|
def lowest_resolvable_security_fix_version
|
39
46
|
return if git_dependency?
|
40
47
|
return nil if version_comes_from_multi_dependency_property?
|
@@ -43,6 +50,7 @@ module Dependabot
|
|
43
50
|
lowest_security_fix_version
|
44
51
|
end
|
45
52
|
|
53
|
+
sig { override.returns(T.nilable(Dependabot::Version)) }
|
46
54
|
def latest_resolvable_version_with_no_unlock
|
47
55
|
# Irrelevant, since Gradle has a single dependency file.
|
48
56
|
#
|
@@ -54,6 +62,7 @@ module Dependabot
|
|
54
62
|
nil
|
55
63
|
end
|
56
64
|
|
65
|
+
sig { override.returns(T::Array[T::Hash[Symbol, T.untyped]]) }
|
57
66
|
def updated_requirements
|
58
67
|
property_names =
|
59
68
|
declarations_using_a_property
|
@@ -67,6 +76,7 @@ module Dependabot
|
|
67
76
|
).updated_requirements
|
68
77
|
end
|
69
78
|
|
79
|
+
sig { override.returns(T::Boolean) }
|
70
80
|
def requirements_unlocked_or_can_be?
|
71
81
|
# If the dependency version come from a property we couldn't
|
72
82
|
# interpolate then there's nothing we can do.
|
@@ -75,6 +85,7 @@ module Dependabot
|
|
75
85
|
|
76
86
|
private
|
77
87
|
|
88
|
+
sig { override.returns(T::Boolean) }
|
78
89
|
def latest_version_resolvable_with_full_unlock?
|
79
90
|
unless version_comes_from_multi_dependency_property? ||
|
80
91
|
version_comes_from_dependency_set?
|
@@ -84,39 +95,51 @@ module Dependabot
|
|
84
95
|
multi_dependency_updater.update_possible?
|
85
96
|
end
|
86
97
|
|
98
|
+
sig { override.returns(T::Array[Dependabot::Dependency]) }
|
87
99
|
def updated_dependencies_after_full_unlock
|
88
100
|
multi_dependency_updater.updated_dependencies
|
89
101
|
end
|
90
102
|
|
103
|
+
sig { override.returns(T::Boolean) }
|
91
104
|
def numeric_version_up_to_date?
|
92
105
|
return false unless version_class.correct?(dependency.version)
|
93
106
|
|
94
107
|
super
|
95
108
|
end
|
96
109
|
|
110
|
+
sig { override.params(requirements_to_unlock: T.nilable(Symbol)).returns(T::Boolean) }
|
97
111
|
def numeric_version_can_update?(requirements_to_unlock:)
|
98
112
|
return false unless version_class.correct?(dependency.version)
|
99
113
|
|
100
114
|
super
|
101
115
|
end
|
102
116
|
|
117
|
+
sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
103
118
|
def preferred_version_details
|
104
119
|
return lowest_security_fix_version_details if vulnerable?
|
105
120
|
|
106
121
|
latest_version_details
|
107
122
|
end
|
108
123
|
|
124
|
+
sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
109
125
|
def latest_version_details
|
110
|
-
@latest_version_details ||=
|
126
|
+
@latest_version_details ||= T.let(
|
127
|
+
version_finder.latest_version_details,
|
128
|
+
T.nilable(T::Hash[Symbol, T.untyped])
|
129
|
+
)
|
111
130
|
end
|
112
131
|
|
132
|
+
sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
113
133
|
def lowest_security_fix_version_details
|
114
|
-
@lowest_security_fix_version_details ||=
|
115
|
-
version_finder.lowest_security_fix_version_details
|
134
|
+
@lowest_security_fix_version_details ||= T.let(
|
135
|
+
version_finder.lowest_security_fix_version_details,
|
136
|
+
T.nilable(T::Hash[Symbol, T.untyped])
|
137
|
+
)
|
116
138
|
end
|
117
139
|
|
140
|
+
sig { returns(VersionFinder) }
|
118
141
|
def version_finder
|
119
|
-
@version_finder ||=
|
142
|
+
@version_finder ||= T.let(
|
120
143
|
VersionFinder.new(
|
121
144
|
dependency: dependency,
|
122
145
|
dependency_files: dependency_files,
|
@@ -125,11 +148,14 @@ module Dependabot
|
|
125
148
|
raise_on_ignored: raise_on_ignored,
|
126
149
|
cooldown_options: update_cooldown,
|
127
150
|
security_advisories: security_advisories
|
128
|
-
)
|
151
|
+
),
|
152
|
+
T.nilable(VersionFinder)
|
153
|
+
)
|
129
154
|
end
|
130
155
|
|
156
|
+
sig { returns(MultiDependencyUpdater) }
|
131
157
|
def multi_dependency_updater
|
132
|
-
@multi_dependency_updater ||=
|
158
|
+
@multi_dependency_updater ||= T.let(
|
133
159
|
MultiDependencyUpdater.new(
|
134
160
|
dependency: dependency,
|
135
161
|
dependency_files: dependency_files,
|
@@ -137,21 +163,28 @@ module Dependabot
|
|
137
163
|
target_version_details: latest_version_details,
|
138
164
|
ignored_versions: ignored_versions,
|
139
165
|
raise_on_ignored: raise_on_ignored
|
140
|
-
)
|
166
|
+
),
|
167
|
+
T.nilable(MultiDependencyUpdater)
|
168
|
+
)
|
141
169
|
end
|
142
170
|
|
171
|
+
sig { returns(T::Boolean) }
|
143
172
|
def git_dependency?
|
144
173
|
git_commit_checker.git_dependency?
|
145
174
|
end
|
146
175
|
|
176
|
+
sig { returns(Dependabot::GitCommitChecker) }
|
147
177
|
def git_commit_checker
|
148
|
-
@git_commit_checker ||=
|
178
|
+
@git_commit_checker ||= T.let(
|
149
179
|
GitCommitChecker.new(
|
150
180
|
dependency: dependency,
|
151
181
|
credentials: credentials
|
152
|
-
)
|
182
|
+
),
|
183
|
+
T.nilable(Dependabot::GitCommitChecker)
|
184
|
+
)
|
153
185
|
end
|
154
186
|
|
187
|
+
sig { returns(T::Boolean) }
|
155
188
|
def version_comes_from_multi_dependency_property?
|
156
189
|
declarations_using_a_property.any? do |requirement|
|
157
190
|
property_name = requirement.fetch(:metadata).fetch(:property_name)
|
@@ -166,26 +199,33 @@ module Dependabot
|
|
166
199
|
end
|
167
200
|
end
|
168
201
|
|
202
|
+
sig { returns(T::Boolean) }
|
169
203
|
def version_comes_from_dependency_set?
|
170
204
|
dependency.requirements.any? do |req|
|
171
205
|
req.dig(:metadata, :dependency_set)
|
172
206
|
end
|
173
207
|
end
|
174
208
|
|
209
|
+
sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
|
175
210
|
def declarations_using_a_property
|
176
|
-
@declarations_using_a_property ||=
|
211
|
+
@declarations_using_a_property ||= T.let(
|
177
212
|
dependency.requirements
|
178
|
-
.select { |req| req.dig(:metadata, :property_name) }
|
213
|
+
.select { |req| req.dig(:metadata, :property_name) },
|
214
|
+
T.nilable(T::Array[T::Hash[Symbol, T.untyped]])
|
215
|
+
)
|
179
216
|
end
|
180
217
|
|
218
|
+
sig { returns(T::Array[Dependabot::Dependency]) }
|
181
219
|
def all_property_based_dependencies
|
182
|
-
@all_property_based_dependencies ||=
|
220
|
+
@all_property_based_dependencies ||= T.let(
|
183
221
|
Gradle::FileParser.new(
|
184
222
|
dependency_files: dependency_files,
|
185
223
|
source: nil
|
186
224
|
).parse.select do |dep|
|
187
225
|
dep.requirements.any? { |req| req.dig(:metadata, :property_name) }
|
188
|
-
end
|
226
|
+
end,
|
227
|
+
T.nilable(T::Array[Dependabot::Dependency])
|
228
|
+
)
|
189
229
|
end
|
190
230
|
end
|
191
231
|
end
|
@@ -1,6 +1,7 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require "sorbet-runtime"
|
4
5
|
require "dependabot/version"
|
5
6
|
require "dependabot/utils"
|
6
7
|
|
@@ -12,13 +13,15 @@ require "dependabot/utils"
|
|
12
13
|
module Dependabot
|
13
14
|
module Gradle
|
14
15
|
class Version < Dependabot::Version
|
15
|
-
|
16
|
-
|
16
|
+
extend T::Sig
|
17
|
+
|
18
|
+
NULL_VALUES = T.let(%w(0 final ga).freeze, T::Array[String])
|
19
|
+
PREFIXED_TOKEN_HIERARCHY = T.let({
|
17
20
|
"." => { qualifier: 1, number: 4 },
|
18
21
|
"-" => { qualifier: 2, number: 3 },
|
19
22
|
"_" => { qualifier: 2, number: 3 }
|
20
|
-
}.freeze
|
21
|
-
NAMED_QUALIFIERS_HIERARCHY = {
|
23
|
+
}.freeze, T::Hash[String, T::Hash[Symbol, Integer]])
|
24
|
+
NAMED_QUALIFIERS_HIERARCHY = T.let({
|
22
25
|
"a" => 1, "alpha" => 1,
|
23
26
|
"b" => 2, "beta" => 2,
|
24
27
|
"m" => 3, "milestone" => 3,
|
@@ -26,37 +29,44 @@ module Dependabot
|
|
26
29
|
"snapshot" => 5, "dev" => 5,
|
27
30
|
"ga" => 6, "" => 6, "final" => 6,
|
28
31
|
"sp" => 7
|
29
|
-
}.freeze
|
30
|
-
VERSION_PATTERN =
|
32
|
+
}.freeze, T::Hash[String, Integer])
|
33
|
+
VERSION_PATTERN = T.let(
|
31
34
|
"[0-9a-zA-Z]+" \
|
32
35
|
'(?>\.[0-9a-zA-Z]*)*' \
|
33
|
-
'([_\-\+][0-9A-Za-z_-]*(\.[0-9A-Za-z_-]*)*)?'
|
34
|
-
|
36
|
+
'([_\-\+][0-9A-Za-z_-]*(\.[0-9A-Za-z_-]*)*)?',
|
37
|
+
String
|
38
|
+
)
|
39
|
+
ANCHORED_VERSION_PATTERN = T.let(/\A\s*(#{VERSION_PATTERN})?\s*\z/, Regexp)
|
35
40
|
|
41
|
+
sig { override.params(version: T.untyped).returns(T::Boolean) }
|
36
42
|
def self.correct?(version)
|
37
43
|
return false if version.nil?
|
38
44
|
|
39
45
|
version.to_s.match?(ANCHORED_VERSION_PATTERN)
|
40
46
|
end
|
41
47
|
|
48
|
+
sig { override.params(version: T.untyped).void }
|
42
49
|
def initialize(version)
|
43
|
-
@version_string = version.to_s
|
50
|
+
@version_string = T.let(version.to_s, String)
|
44
51
|
super(version.to_s.tr("_", "-"))
|
45
52
|
end
|
46
53
|
|
54
|
+
sig { override.returns(String) }
|
47
55
|
def to_s
|
48
56
|
@version_string
|
49
57
|
end
|
50
58
|
|
59
|
+
sig { override.returns(T::Boolean) }
|
51
60
|
def prerelease?
|
52
61
|
tokens.any? do |token|
|
53
62
|
next true if token == "eap"
|
54
63
|
next false unless NAMED_QUALIFIERS_HIERARCHY[token]
|
55
64
|
|
56
|
-
NAMED_QUALIFIERS_HIERARCHY[token] < 6
|
65
|
+
T.must(NAMED_QUALIFIERS_HIERARCHY[token]) < 6
|
57
66
|
end
|
58
67
|
end
|
59
68
|
|
69
|
+
sig { params(other: T.untyped).returns(Integer) }
|
60
70
|
def <=>(other)
|
61
71
|
version = stringify_version(@version_string)
|
62
72
|
version = fill_tokens(version)
|
@@ -76,10 +86,10 @@ module Dependabot
|
|
76
86
|
|
77
87
|
prefixed_tokens.count.times.each do |index|
|
78
88
|
comp = compare_prefixed_token(
|
79
|
-
prefix: prefixed_tokens[index][0],
|
80
|
-
token: prefixed_tokens[index][1..-1] || "",
|
81
|
-
other_prefix: other_prefixed_tokens[index][0],
|
82
|
-
other_token: other_prefixed_tokens[index][1..-1] || ""
|
89
|
+
prefix: T.must(T.must(prefixed_tokens[index])[0]),
|
90
|
+
token: T.must(prefixed_tokens[index])[1..-1] || "",
|
91
|
+
other_prefix: T.must(T.must(other_prefixed_tokens[index])[0]),
|
92
|
+
other_token: T.must(other_prefixed_tokens[index])[1..-1] || ""
|
83
93
|
)
|
84
94
|
return comp unless comp.zero?
|
85
95
|
end
|
@@ -89,16 +99,21 @@ module Dependabot
|
|
89
99
|
|
90
100
|
private
|
91
101
|
|
102
|
+
sig { returns(T::Array[String]) }
|
92
103
|
def tokens
|
93
|
-
@tokens ||=
|
104
|
+
@tokens ||= T.let(
|
94
105
|
begin
|
95
106
|
version = @version_string.to_s.downcase
|
96
107
|
version = fill_tokens(version)
|
97
108
|
version = trim_version(version)
|
98
|
-
split_into_prefixed_tokens(version).map { |t| t[1..-1] }
|
99
|
-
end
|
109
|
+
split_into_prefixed_tokens(version).map { |t| T.must(t[1..-1]) }
|
110
|
+
end,
|
111
|
+
T.nilable(T::Array[String])
|
112
|
+
)
|
113
|
+
@tokens
|
100
114
|
end
|
101
115
|
|
116
|
+
sig { params(version: T.untyped).returns(String) }
|
102
117
|
def stringify_version(version)
|
103
118
|
version = version.to_s.downcase
|
104
119
|
|
@@ -106,6 +121,7 @@ module Dependabot
|
|
106
121
|
version.gsub(/^v(?=\d)/, "")
|
107
122
|
end
|
108
123
|
|
124
|
+
sig { params(version: String).returns(String) }
|
109
125
|
def fill_tokens(version)
|
110
126
|
# Add separators when transitioning from digits to characters
|
111
127
|
version = version.gsub(/(\d)([A-Za-z])/, '\1-\2')
|
@@ -117,14 +133,16 @@ module Dependabot
|
|
117
133
|
version.gsub(/([\.\-])$/, '\10')
|
118
134
|
end
|
119
135
|
|
136
|
+
sig { params(version: String).returns(String) }
|
120
137
|
def trim_version(version)
|
121
138
|
version.split("-").filter_map do |v|
|
122
139
|
parts = v.split(".")
|
123
|
-
parts = parts[0..-2] while NULL_VALUES.include?(parts
|
124
|
-
parts
|
140
|
+
parts = T.must(parts[0..-2]) while NULL_VALUES.include?(parts.last)
|
141
|
+
parts.join(".")
|
125
142
|
end.reject(&:empty?).join("-")
|
126
143
|
end
|
127
144
|
|
145
|
+
sig { params(version: String, other_version: String).returns([String, String]) }
|
128
146
|
def convert_dates(version, other_version)
|
129
147
|
default = [version, other_version]
|
130
148
|
return default unless version.match?(/^\d{4}-?\d{2}-?\d{2}$/)
|
@@ -133,26 +151,34 @@ module Dependabot
|
|
133
151
|
[version.delete("-"), other_version.delete("-")]
|
134
152
|
end
|
135
153
|
|
154
|
+
sig { params(version: String).returns(T::Array[String]) }
|
136
155
|
def split_into_prefixed_tokens(version)
|
137
156
|
".#{version}".split(/(?=[_\-\.])/)
|
138
157
|
end
|
139
158
|
|
159
|
+
sig do
|
160
|
+
params(
|
161
|
+
prefixed_tokens: T::Array[String],
|
162
|
+
other_prefixed_tokens: T::Array[String]
|
163
|
+
).returns([T::Array[String], T::Array[String]])
|
164
|
+
end
|
140
165
|
def pad_for_comparison(prefixed_tokens, other_prefixed_tokens)
|
141
166
|
prefixed_tokens = prefixed_tokens.dup
|
142
167
|
other_prefixed_tokens = other_prefixed_tokens.dup
|
143
168
|
|
144
|
-
longest = [prefixed_tokens, other_prefixed_tokens].max_by(&:count)
|
145
|
-
shortest = [prefixed_tokens, other_prefixed_tokens].min_by(&:count)
|
169
|
+
longest = T.must([prefixed_tokens, other_prefixed_tokens].max_by(&:count))
|
170
|
+
shortest = T.must([prefixed_tokens, other_prefixed_tokens].min_by(&:count))
|
146
171
|
|
147
172
|
longest.count.times do |index|
|
148
173
|
next unless shortest[index].nil?
|
149
174
|
|
150
|
-
shortest[index] = longest[index].start_with?(".") ? ".0" : "-"
|
175
|
+
shortest[index] = T.must(longest[index]).start_with?(".") ? ".0" : "-"
|
151
176
|
end
|
152
177
|
|
153
178
|
[prefixed_tokens, other_prefixed_tokens]
|
154
179
|
end
|
155
180
|
|
181
|
+
sig { params(prefix: String, token: String, other_prefix: String, other_token: String).returns(Integer) }
|
156
182
|
def compare_prefixed_token(prefix:, token:, other_prefix:, other_token:)
|
157
183
|
return 1 if token == "+" && other_token != "+"
|
158
184
|
return -1 if other_token == "+" && token != "+"
|
@@ -171,18 +197,21 @@ module Dependabot
|
|
171
197
|
compare_token(token: token, other_token: other_token)
|
172
198
|
end
|
173
199
|
|
200
|
+
sig { params(token: String, other_token: String).returns(Integer) }
|
174
201
|
def compare_token(token:, other_token:)
|
175
202
|
if (token_hierarchy = NAMED_QUALIFIERS_HIERARCHY[token])
|
176
203
|
return -1 unless NAMED_QUALIFIERS_HIERARCHY[other_token]
|
177
204
|
|
178
|
-
return token_hierarchy <=> NAMED_QUALIFIERS_HIERARCHY[other_token]
|
205
|
+
return token_hierarchy <=> T.must(NAMED_QUALIFIERS_HIERARCHY[other_token])
|
179
206
|
end
|
180
207
|
|
181
208
|
return 1 if NAMED_QUALIFIERS_HIERARCHY[other_token]
|
182
209
|
|
183
|
-
|
184
|
-
|
185
|
-
|
210
|
+
if token.match?(/^\d+$/) && other_token.match?(/^\d+$/)
|
211
|
+
token.to_i <=> other_token.to_i
|
212
|
+
else
|
213
|
+
(token <=> other_token) || 0
|
214
|
+
end
|
186
215
|
end
|
187
216
|
end
|
188
217
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dependabot-gradle
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.321.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dependabot
|
@@ -15,28 +15,28 @@ dependencies:
|
|
15
15
|
requirements:
|
16
16
|
- - '='
|
17
17
|
- !ruby/object:Gem::Version
|
18
|
-
version: 0.
|
18
|
+
version: 0.321.0
|
19
19
|
type: :runtime
|
20
20
|
prerelease: false
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
22
22
|
requirements:
|
23
23
|
- - '='
|
24
24
|
- !ruby/object:Gem::Version
|
25
|
-
version: 0.
|
25
|
+
version: 0.321.0
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: dependabot-maven
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
29
29
|
requirements:
|
30
30
|
- - '='
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: 0.
|
32
|
+
version: 0.321.0
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
37
|
- - '='
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: 0.
|
39
|
+
version: 0.321.0
|
40
40
|
- !ruby/object:Gem::Dependency
|
41
41
|
name: debug
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
@@ -280,7 +280,7 @@ licenses:
|
|
280
280
|
- MIT
|
281
281
|
metadata:
|
282
282
|
bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
|
283
|
-
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.
|
283
|
+
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.321.0
|
284
284
|
rdoc_options: []
|
285
285
|
require_paths:
|
286
286
|
- lib
|