env_parser 1.3.1 → 1.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +1 -1
- data/.rubocop.yml +22 -35
- data/.ruby-version +1 -1
- data/Gemfile.lock +44 -42
- data/README.md +1 -1
- data/docs/EnvParser/AutoregisterFileNotFound.html +6 -6
- data/docs/EnvParser/Error.html +5 -6
- data/docs/EnvParser/TypeAlreadyDefinedError.html +5 -6
- data/docs/EnvParser/Types/BaseTypes.html +9 -7
- data/docs/EnvParser/Types/ChronologyTypes.html +7 -6
- data/docs/EnvParser/Types/InternetTypes.html +7 -6
- data/docs/EnvParser/Types.html +6 -6
- data/docs/EnvParser/UnknownTypeError.html +5 -6
- data/docs/EnvParser/UnparseableAutoregisterSpec.html +6 -6
- data/docs/EnvParser/ValueNotAllowedError.html +7 -6
- data/docs/EnvParser/ValueNotConvertibleError.html +5 -6
- data/docs/EnvParser.html +117 -121
- data/docs/_index.html +5 -7
- data/docs/file.README.html +241 -143
- data/docs/frames.html +1 -1
- data/docs/index.html +241 -143
- data/docs/method_list.html +1 -9
- data/docs/top-level-namespace.html +4 -82
- data/env_parser.gemspec +14 -14
- data/lib/env_parser/errors.rb +18 -18
- data/lib/env_parser/types/base_types.rb +69 -69
- data/lib/env_parser/types/chronology_types.rb +54 -54
- data/lib/env_parser/types/internet_types.rb +50 -50
- data/lib/env_parser/types.rb +2 -2
- data/lib/env_parser/version.rb +1 -1
- data/lib/env_parser.rb +205 -213
- data/spec/env_parser/types/base_types_spec.rb +98 -0
- data/spec/env_parser/types/chronology_types_spec.rb +49 -0
- data/spec/env_parser/types/internet_types_spec.rb +45 -0
- data/spec/env_parser_spec.rb +192 -0
- data/spec/spec_helper.rb +14 -0
- metadata +53 -48
- data/.travis.yml +0 -5
@@ -6,7 +6,7 @@
|
|
6
6
|
<title>
|
7
7
|
Top Level Namespace
|
8
8
|
|
9
|
-
— Documentation by YARD 0.9.
|
9
|
+
— Documentation by YARD 0.9.28
|
10
10
|
|
11
11
|
</title>
|
12
12
|
|
@@ -95,92 +95,14 @@
|
|
95
95
|
|
96
96
|
|
97
97
|
|
98
|
-
|
99
|
-
<h2>
|
100
|
-
Instance Method Summary
|
101
|
-
<small><a href="#" class="summary_toggle">collapse</a></small>
|
102
|
-
</h2>
|
103
|
-
|
104
|
-
<ul class="summary">
|
105
|
-
|
106
|
-
<li class="public ">
|
107
|
-
<span class="summary_signature">
|
108
|
-
|
109
|
-
<a href="top-level-namespace.html#filename-instance_method" title="#filename (instance method)">#<strong>filename</strong> ⇒ Object </a>
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
</span>
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
<span class="summary_desc"><div class='inline'>
|
124
|
-
<p>Load all files listed in “/lib/env_parser/types”.</p>
|
125
|
-
</div></span>
|
126
|
-
|
127
|
-
</li>
|
128
|
-
|
129
|
-
|
130
|
-
</ul>
|
131
|
-
|
132
|
-
|
133
|
-
|
134
98
|
|
135
|
-
<div id="instance_method_details" class="method_details_list">
|
136
|
-
<h2>Instance Method Details</h2>
|
137
|
-
|
138
|
-
|
139
|
-
<div class="method_details first">
|
140
|
-
<h3 class="signature first" id="filename-instance_method">
|
141
|
-
|
142
|
-
#<strong>filename</strong> ⇒ <tt>Object</tt>
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
</h3><div class="docstring">
|
149
|
-
<div class="discussion">
|
150
|
-
|
151
|
-
<p>Load all files listed in “/lib/env_parser/types”.</p>
|
152
|
-
|
153
|
-
|
154
|
-
</div>
|
155
|
-
</div>
|
156
|
-
<div class="tags">
|
157
|
-
|
158
|
-
|
159
|
-
</div><table class="source_code">
|
160
|
-
<tr>
|
161
|
-
<td>
|
162
|
-
<pre class="lines">
|
163
|
-
|
164
|
-
|
165
|
-
3</pre>
|
166
|
-
</td>
|
167
|
-
<td>
|
168
|
-
<pre class="code"><span class="info file"># File 'lib/env_parser/types.rb', line 3</span>
|
169
|
-
|
170
|
-
<span class='const'>Dir</span><span class='period'>.</span><span class='id identifier rubyid_glob'>glob</span><span class='lparen'>(</span><span class='const'>File</span><span class='period'>.</span><span class='id identifier rubyid_join'>join</span><span class='lparen'>(</span><span class='id identifier rubyid___dir__'>__dir__</span><span class='comma'>,</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>types</span><span class='tstring_end'>'</span></span><span class='comma'>,</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>*.rb</span><span class='tstring_end'>'</span></span><span class='rparen'>)</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_each'>each</span> <span class='lbrace'>{</span> <span class='op'>|</span><span class='id identifier rubyid_filename'>filename</span><span class='op'>|</span> <span class='id identifier rubyid_require_relative'>require_relative</span> <span class='id identifier rubyid_filename'>filename</span> <span class='rbrace'>}</span></pre>
|
171
|
-
</td>
|
172
|
-
</tr>
|
173
|
-
</table>
|
174
|
-
</div>
|
175
|
-
|
176
|
-
</div>
|
177
99
|
|
178
100
|
</div>
|
179
101
|
|
180
102
|
<div id="footer">
|
181
|
-
Generated on
|
182
|
-
<a href="
|
183
|
-
0.9.
|
103
|
+
Generated on Sun Dec 25 19:19:23 2022 by
|
104
|
+
<a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
105
|
+
0.9.28 (ruby-3.0.4).
|
184
106
|
</div>
|
185
107
|
|
186
108
|
</div>
|
data/env_parser.gemspec
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
-
|
2
|
-
lib = File.expand_path('../lib', __FILE__)
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
3
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
3
|
require 'env_parser/version'
|
5
4
|
|
6
5
|
Gem::Specification.new do |spec|
|
6
|
+
spec.required_ruby_version = '~> 3.0'
|
7
|
+
|
7
8
|
spec.name = 'env_parser'
|
8
9
|
spec.version = EnvParser::VERSION
|
9
10
|
spec.authors = ['Nestor Custodio']
|
@@ -13,21 +14,20 @@ Gem::Specification.new do |spec|
|
|
13
14
|
spec.homepage = 'https://github.com/nestor-custodio/env_parser'
|
14
15
|
spec.license = 'MIT'
|
15
16
|
|
16
|
-
spec.files = `git ls-files -z`.split("\x0").reject
|
17
|
-
|
18
|
-
end
|
19
|
-
spec.bindir = 'exe'
|
20
|
-
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |filename| filename.start_with? 'test/' }
|
18
|
+
spec.executables = []
|
21
19
|
spec.require_paths = ['lib']
|
22
20
|
|
23
|
-
spec.
|
24
|
-
spec.add_development_dependency 'rake'
|
25
|
-
spec.add_development_dependency 'rspec', '~> 3.0'
|
26
|
-
spec.add_development_dependency 'rspec_junit_formatter'
|
27
|
-
spec.add_development_dependency 'rubocop', '1.7'
|
28
|
-
spec.add_development_dependency 'yard'
|
21
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
29
22
|
|
30
|
-
spec.add_dependency 'activesupport', '>=
|
23
|
+
spec.add_dependency 'activesupport', '>= 6.1.0'
|
31
24
|
spec.add_dependency 'chronic'
|
32
25
|
spec.add_dependency 'chronic_duration'
|
26
|
+
|
27
|
+
spec.add_development_dependency 'bundler', '~> 2'
|
28
|
+
spec.add_development_dependency 'rake'
|
29
|
+
spec.add_development_dependency 'rspec', '~> 3'
|
30
|
+
spec.add_development_dependency 'rspec_junit_formatter'
|
31
|
+
spec.add_development_dependency 'rubocop'
|
32
|
+
spec.add_development_dependency 'yard'
|
33
33
|
end
|
data/lib/env_parser/errors.rb
CHANGED
@@ -1,40 +1,40 @@
|
|
1
1
|
class EnvParser
|
2
|
-
|
3
|
-
|
2
|
+
# Base error class for EnvParser.
|
3
|
+
#
|
4
4
|
class Error < ::StandardError
|
5
5
|
end
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
# Error class used to indicate a type has already been defined.
|
8
|
+
#
|
9
9
|
class TypeAlreadyDefinedError < Error
|
10
10
|
end
|
11
11
|
|
12
|
-
|
13
|
-
|
12
|
+
# Error class used to indicate the requested "as" type has not been defined.
|
13
|
+
#
|
14
14
|
class UnknownTypeError < Error
|
15
15
|
end
|
16
16
|
|
17
|
-
|
18
|
-
|
17
|
+
# Error class used to indicate value given is not convertible to the requested type.
|
18
|
+
#
|
19
19
|
class ValueNotConvertibleError < Error
|
20
20
|
end
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
# Error class used to indicate parsed values that do not pass user-validation, either by not
|
23
|
+
# being part of the given "from_set" list, or by failing the "validated_by" Proc or yield-block
|
24
|
+
# check.
|
25
|
+
#
|
26
26
|
class ValueNotAllowedError < Error
|
27
27
|
end
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
# Error class used to indicate a missing auto-registration spec file (used by the "autoregister"
|
30
|
+
# feature).
|
31
|
+
#
|
32
32
|
class AutoregisterFileNotFound < Error
|
33
33
|
end
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
35
|
+
# Error class used to indicate an unparseable auto-registration spec (used by the "autoregister"
|
36
|
+
# feature).
|
37
|
+
#
|
38
38
|
class UnparseableAutoregisterSpec < Error
|
39
39
|
end
|
40
40
|
end
|
@@ -1,75 +1,75 @@
|
|
1
1
|
require 'env_parser'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
# The parent module for all EnvParser type definition modules.
|
4
|
+
# Exists only for documentation's sake.
|
5
|
+
#
|
6
6
|
module EnvParser::Types
|
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
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
7
|
+
# Defines types for primitive classes, adding the following:
|
8
|
+
#
|
9
|
+
# <table>
|
10
|
+
# <tbody>
|
11
|
+
# <tr>
|
12
|
+
# <th><code>:as</code> value</th>
|
13
|
+
# <th>type returned</th>
|
14
|
+
# <th>default</th>
|
15
|
+
# <th>notes</th>
|
16
|
+
# </tr>
|
17
|
+
# </tbody>
|
18
|
+
# <tbody>
|
19
|
+
# <tr>
|
20
|
+
# <td>:string</td>
|
21
|
+
# <td>String</td>
|
22
|
+
# <td><code>''</code></td>
|
23
|
+
# <td></td>
|
24
|
+
# </tr>
|
25
|
+
# <tr>
|
26
|
+
# <td>:symbol</td>
|
27
|
+
# <td>Symbol</td>
|
28
|
+
# <td><code>:''</code></td>
|
29
|
+
# <td></td>
|
30
|
+
# </tr>
|
31
|
+
# <tr>
|
32
|
+
# <td>:boolean</td>
|
33
|
+
# <td>TrueValue / FalseValue</td>
|
34
|
+
# <td><code>false</code></td>
|
35
|
+
# <td></td>
|
36
|
+
# </tr>
|
37
|
+
# <tr>
|
38
|
+
# <td>:int / :integer</td>
|
39
|
+
# <td>Integer</td>
|
40
|
+
# <td><code>0</code></td>
|
41
|
+
# <td></td>
|
42
|
+
# </tr>
|
43
|
+
# <tr>
|
44
|
+
# <td>:float / :decimal / :number</td>
|
45
|
+
# <td>Float</td>
|
46
|
+
# <td><code>0.0</code></td>
|
47
|
+
# <td></td>
|
48
|
+
# </tr>
|
49
|
+
# <tr>
|
50
|
+
# <td>:json</td>
|
51
|
+
# <td>< depends on JSON given ></td>
|
52
|
+
# <td><code>nil</code></td>
|
53
|
+
# <td></td>
|
54
|
+
# </tr>
|
55
|
+
# <tr>
|
56
|
+
# <td>:array</td>
|
57
|
+
# <td>Array</td>
|
58
|
+
# <td><code>[]</code></td>
|
59
|
+
# <td></td>
|
60
|
+
# </tr>
|
61
|
+
# <tr>
|
62
|
+
# <td>:hash</td>
|
63
|
+
# <td>Hash</td>
|
64
|
+
# <td><code>{}</code></td>
|
65
|
+
# <td></td>
|
66
|
+
# </tr>
|
67
|
+
# </tbody>
|
68
|
+
# </table>
|
69
|
+
#
|
70
|
+
# Note JSON is parsed using *quirks-mode* (meaning 'true', '25', and 'null' are all considered
|
71
|
+
# valid, parseable JSON).
|
72
|
+
#
|
73
73
|
module BaseTypes
|
74
74
|
EnvParser.define_type(:string, if_unset: '') do |value|
|
75
75
|
value
|
@@ -1,56 +1,56 @@
|
|
1
1
|
require 'env_parser'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
# The parent module for all EnvParser type definition modules.
|
4
|
+
# Exists only for documentation's sake.
|
5
|
+
#
|
6
6
|
module EnvParser::Types
|
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
|
-
|
7
|
+
# Defines types for date/time-related values, adding the following:
|
8
|
+
#
|
9
|
+
# <table>
|
10
|
+
# <tbody>
|
11
|
+
# <tr>
|
12
|
+
# <th><code>:as</code> value</th>
|
13
|
+
# <th>type returned</th>
|
14
|
+
# <th>default</th>
|
15
|
+
# <th>notes</th>
|
16
|
+
# </tr>
|
17
|
+
# </tbody>
|
18
|
+
# <tbody>
|
19
|
+
# <tr>
|
20
|
+
# <td>:date</td>
|
21
|
+
# <td>Date</td>
|
22
|
+
# <td><code>nil</code></td>
|
23
|
+
# <td>
|
24
|
+
# A natural language or ISO8601-parseable date.
|
25
|
+
# <br />
|
26
|
+
# Actual interpretation of the value is handled by the *chronic* gem.
|
27
|
+
# </td>
|
28
|
+
# </tr>
|
29
|
+
# <tr>
|
30
|
+
# <td>:time / :datetime</td>
|
31
|
+
# <td>Time</td>
|
32
|
+
# <td><code>nil</code></td>
|
33
|
+
# <td>
|
34
|
+
# A natural language or ISO8601-parseable date and time.
|
35
|
+
# <br />
|
36
|
+
# Actual interpretation of the value is handled by the *chronic* gem.
|
37
|
+
# </td>
|
38
|
+
# </tr>
|
39
|
+
# <tr>
|
40
|
+
# <td>:duration</td>
|
41
|
+
# <td>Numeric</td>
|
42
|
+
# <td><code>nil</code></td>
|
43
|
+
# <td>
|
44
|
+
# A natural language or ISO8601-parseable period.
|
45
|
+
# <br />
|
46
|
+
# Value returned is the number of seconds in the given period.
|
47
|
+
# <br />
|
48
|
+
# Actual interpretation of the value is handled by the *chronic_duration* gem.
|
49
|
+
# </td>
|
50
|
+
# </tr>
|
51
|
+
# </tbody>
|
52
|
+
# </table>
|
53
|
+
#
|
54
54
|
module ChronologyTypes
|
55
55
|
EnvParser.define_type(:date, if_unset: nil) do |value|
|
56
56
|
require 'chronic'
|
@@ -85,10 +85,10 @@ module EnvParser::Types
|
|
85
85
|
original_raise_setting = ChronicDuration.raise_exceptions
|
86
86
|
ChronicDuration.raise_exceptions = true
|
87
87
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
iso_period = %r{^\s*P(?:[0-9.]Y)?(?:[0-9.]M)?(?:[0-9.]W)?(?:[0-9.]D)?(?:T(?:[0-9.]H)?(?:[0-9.]M)?(?:[0-9.]S)?)?\s*$}
|
88
|
+
# With `raise_exceptions` set, ChronicDuration will fail on the "P" and "T" in ISO8601
|
89
|
+
# periods, so we have to check for and remove them.
|
90
|
+
#
|
91
|
+
iso_period = %r{^\s*P(?:[0-9.]Y)?(?:[0-9.]M)?(?:[0-9.]W)?(?:[0-9.]D)?(?:T(?:[0-9.]H)?(?:[0-9.]M)?(?:[0-9.]S)?)?\s*$}
|
92
92
|
value = value.delete 'PT' if value =~ iso_period
|
93
93
|
|
94
94
|
value = ChronicDuration.parse value, keep_zero: true
|
@@ -1,56 +1,56 @@
|
|
1
1
|
require 'env_parser'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
# The parent module for all EnvParser type definition modules.
|
4
|
+
# Exists only for documentation's sake.
|
5
|
+
#
|
6
6
|
module EnvParser::Types
|
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
|
-
|
7
|
+
# Defines types for internet-related values, adding the following:
|
8
|
+
#
|
9
|
+
# <table>
|
10
|
+
# <tbody>
|
11
|
+
# <tr>
|
12
|
+
# <th><code>:as</code> value</th>
|
13
|
+
# <th>type returned</th>
|
14
|
+
# <th>default</th>
|
15
|
+
# <th>notes</th>
|
16
|
+
# </tr>
|
17
|
+
# </tbody>
|
18
|
+
# <tbody>
|
19
|
+
# <tr>
|
20
|
+
# <td>:ipv4_address</td>
|
21
|
+
# <td>String</td>
|
22
|
+
# <td><code>nil</code></td>
|
23
|
+
# <td>
|
24
|
+
# An IPv4 address in 4-octet dot-decimal notation,
|
25
|
+
# <br />
|
26
|
+
# with no CIDR or subnet suffix (e.g. <code>'192.168.0.1'</code>).
|
27
|
+
# </td>
|
28
|
+
# </tr>
|
29
|
+
# <tr>
|
30
|
+
# <td>:ipv6_address</td>
|
31
|
+
# <td>String</td>
|
32
|
+
# <td><code>nil</code></td>
|
33
|
+
# <td>An IPv6 address, in RFC5952 format.</td>
|
34
|
+
# </tr>
|
35
|
+
# <tr>
|
36
|
+
# <td>:network_port / :port</td>
|
37
|
+
# <td>Integer</td>
|
38
|
+
# <td><code>nil</code></td>
|
39
|
+
# <td></td>
|
40
|
+
# </tr>
|
41
|
+
# <tr>
|
42
|
+
# <td>:email_address</td>
|
43
|
+
# <td>String</td>
|
44
|
+
# <td><code>nil</code></td>
|
45
|
+
# <td>
|
46
|
+
# A "simple" email address, containing only a username and a domain.
|
47
|
+
# <br />
|
48
|
+
# Note this does not guarantee RFC5322-conformity.
|
49
|
+
# </td>
|
50
|
+
# </tr>
|
51
|
+
# </tbody>
|
52
|
+
# </table>
|
53
|
+
#
|
54
54
|
module InternetTypes
|
55
55
|
EnvParser.define_type(:ipv4_address, if_unset: nil) do |value|
|
56
56
|
begin
|
data/lib/env_parser/types.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# Load all files listed in "/lib/env_parser/types".
|
2
|
+
#
|
3
3
|
Dir.glob(File.join(__dir__, 'types', '*.rb')).each { |filename| require_relative filename }
|
data/lib/env_parser/version.rb
CHANGED