9ad0a635ed82adfb9db1263eb9a7312eb84d8048
[sdc/sdc-distribution-client.git] /
1 # Copyright 2014 Donald Stufft
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 from __future__ import absolute_import, division, print_function
15
16 import abc
17 import functools
18 import itertools
19 import re
20
21 from ._compat import string_types, with_metaclass
22 from .version import Version, LegacyVersion, parse
23
24
25 class InvalidSpecifier(ValueError):
26     """
27     An invalid specifier was found, users should refer to PEP 440.
28     """
29
30
31 class BaseSpecifier(with_metaclass(abc.ABCMeta, object)):
32
33     @abc.abstractmethod
34     def __str__(self):
35         """
36         Returns the str representation of this Specifier like object. This
37         should be representative of the Specifier itself.
38         """
39
40     @abc.abstractmethod
41     def __hash__(self):
42         """
43         Returns a hash value for this Specifier like object.
44         """
45
46     @abc.abstractmethod
47     def __eq__(self, other):
48         """
49         Returns a boolean representing whether or not the two Specifier like
50         objects are equal.
51         """
52
53     @abc.abstractmethod
54     def __ne__(self, other):
55         """
56         Returns a boolean representing whether or not the two Specifier like
57         objects are not equal.
58         """
59
60     @abc.abstractproperty
61     def prereleases(self):
62         """
63         Returns whether or not pre-releases as a whole are allowed by this
64         specifier.
65         """
66
67     @prereleases.setter
68     def prereleases(self, value):
69         """
70         Sets whether or not pre-releases as a whole are allowed by this
71         specifier.
72         """
73
74     @abc.abstractmethod
75     def contains(self, item, prereleases=None):
76         """
77         Determines if the given item is contained within this specifier.
78         """
79
80     @abc.abstractmethod
81     def filter(self, iterable, prereleases=None):
82         """
83         Takes an iterable of items and filters them so that only items which
84         are contained within this specifier are allowed in it.
85         """
86
87
88 class _IndividualSpecifier(BaseSpecifier):
89
90     _operators = {}
91
92     def __init__(self, spec="", prereleases=None):
93         match = self._regex.search(spec)
94         if not match:
95             raise InvalidSpecifier("Invalid specifier: '{0}'".format(spec))
96
97         self._spec = (
98             match.group("operator").strip(),
99             match.group("version").strip(),
100         )
101
102         # Store whether or not this Specifier should accept prereleases
103         self._prereleases = prereleases
104
105     def __repr__(self):
106         pre = (
107             ", prereleases={0!r}".format(self.prereleases)
108             if self._prereleases is not None
109             else ""
110         )
111
112         return "<{0}({1!r}{2})>".format(
113             self.__class__.__name__,
114             str(self),
115             pre,
116         )
117
118     def __str__(self):
119         return "{0}{1}".format(*self._spec)
120
121     def __hash__(self):
122         return hash(self._spec)
123
124     def __eq__(self, other):
125         if isinstance(other, string_types):
126             try:
127                 other = self.__class__(other)
128             except InvalidSpecifier:
129                 return NotImplemented
130         elif not isinstance(other, self.__class__):
131             return NotImplemented
132
133         return self._spec == other._spec
134
135     def __ne__(self, other):
136         if isinstance(other, string_types):
137             try:
138                 other = self.__class__(other)
139             except InvalidSpecifier:
140                 return NotImplemented
141         elif not isinstance(other, self.__class__):
142             return NotImplemented
143
144         return self._spec != other._spec
145
146     def _get_operator(self, op):
147         return getattr(self, "_compare_{0}".format(self._operators[op]))
148
149     def _coerce_version(self, version):
150         if not isinstance(version, (LegacyVersion, Version)):
151             version = parse(version)
152         return version
153
154     @property
155     def prereleases(self):
156         return self._prereleases
157
158     @prereleases.setter
159     def prereleases(self, value):
160         self._prereleases = value
161
162     def contains(self, item, prereleases=None):
163         # Determine if prereleases are to be allowed or not.
164         if prereleases is None:
165             prereleases = self.prereleases
166
167         # Normalize item to a Version or LegacyVersion, this allows us to have
168         # a shortcut for ``"2.0" in Specifier(">=2")
169         item = self._coerce_version(item)
170
171         # Determine if we should be supporting prereleases in this specifier
172         # or not, if we do not support prereleases than we can short circuit
173         # logic if this version is a prereleases.
174         if item.is_prerelease and not prereleases:
175             return False
176
177         # Actually do the comparison to determine if this item is contained
178         # within this Specifier or not.
179         return self._get_operator(self._spec[0])(item, self._spec[1])
180
181     def filter(self, iterable, prereleases=None):
182         yielded = False
183         found_prereleases = []
184
185         kw = {"prereleases": prereleases if prereleases is not None else True}
186
187         # Attempt to iterate over all the values in the iterable and if any of
188         # them match, yield them.
189         for version in iterable:
190             parsed_version = self._coerce_version(version)
191
192             if self.contains(parsed_version, **kw):
193                 # If our version is a prerelease, and we were not set to allow
194                 # prereleases, then we'll store it for later incase nothing
195                 # else matches this specifier.
196                 if (parsed_version.is_prerelease
197                         and not (prereleases or self.prereleases)):
198                     found_prereleases.append(version)
199                 # Either this is not a prerelease, or we should have been
200                 # accepting prereleases from the begining.
201                 else:
202                     yielded = True
203                     yield version
204
205         # Now that we've iterated over everything, determine if we've yielded
206         # any values, and if we have not and we have any prereleases stored up
207         # then we will go ahead and yield the prereleases.
208         if not yielded and found_prereleases:
209             for version in found_prereleases:
210                 yield version
211
212
213 class LegacySpecifier(_IndividualSpecifier):
214
215     _regex = re.compile(
216         r"""
217         ^
218         \s*
219         (?P<operator>(==|!=|<=|>=|<|>))
220         \s*
221         (?P<version>
222             [^\s]* # We just match everything, except for whitespace since this
223                    # is a "legacy" specifier and the version string can be just
224                    # about anything.
225         )
226         \s*
227         $
228         """,
229         re.VERBOSE | re.IGNORECASE,
230     )
231
232     _operators = {
233         "==": "equal",
234         "!=": "not_equal",
235         "<=": "less_than_equal",
236         ">=": "greater_than_equal",
237         "<": "less_than",
238         ">": "greater_than",
239     }
240
241     def _coerce_version(self, version):
242         if not isinstance(version, LegacyVersion):
243             version = LegacyVersion(str(version))
244         return version
245
246     def _compare_equal(self, prospective, spec):
247         return prospective == self._coerce_version(spec)
248
249     def _compare_not_equal(self, prospective, spec):
250         return prospective != self._coerce_version(spec)
251
252     def _compare_less_than_equal(self, prospective, spec):
253         return prospective <= self._coerce_version(spec)
254
255     def _compare_greater_than_equal(self, prospective, spec):
256         return prospective >= self._coerce_version(spec)
257
258     def _compare_less_than(self, prospective, spec):
259         return prospective < self._coerce_version(spec)
260
261     def _compare_greater_than(self, prospective, spec):
262         return prospective > self._coerce_version(spec)
263
264
265 def _require_version_compare(fn):
266     @functools.wraps(fn)
267     def wrapped(self, prospective, spec):
268         if not isinstance(prospective, Version):
269             return False
270         return fn(self, prospective, spec)
271     return wrapped
272
273
274 class Specifier(_IndividualSpecifier):
275
276     _regex = re.compile(
277         r"""
278         ^
279         \s*
280         (?P<operator>(~=|==|!=|<=|>=|<|>|===))
281         (?P<version>
282             (?:
283                 # The identity operators allow for an escape hatch that will
284                 # do an exact string match of the version you wish to install.
285                 # This will not be parsed by PEP 440 and we cannot determine
286                 # any semantic meaning from it. This operator is discouraged
287                 # but included entirely as an escape hatch.
288                 (?<====)  # Only match for the identity operator
289                 \s*
290                 [^\s]*    # We just match everything, except for whitespace
291                           # since we are only testing for strict identity.
292             )
293             |
294             (?:
295                 # The (non)equality operators allow for wild card and local
296                 # versions to be specified so we have to define these two
297                 # operators separately to enable that.
298                 (?<===|!=)            # Only match for equals and not equals
299
300                 \s*
301                 v?
302                 (?:[0-9]+!)?          # epoch
303                 [0-9]+(?:\.[0-9]+)*   # release
304                 (?:                   # pre release
305                     [-_\.]?
306                     (a|b|c|rc|alpha|beta|pre|preview)
307                     [-_\.]?
308                     [0-9]*
309                 )?
310                 (?:                   # post release
311                     (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
312                 )?
313
314                 # You cannot use a wild card and a dev or local version
315                 # together so group them with a | and make them optional.
316                 (?:
317                     (?:[-_\.]?dev[-_\.]?[0-9]*)?         # dev release
318                     (?:\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*)? # local
319                     |
320                     \.\*  # Wild card syntax of .*
321                 )?
322             )
323             |
324             (?:
325                 # The compatible operator requires at least two digits in the
326                 # release segment.
327                 (?<=~=)               # Only match for the compatible operator
328
329                 \s*
330                 v?
331                 (?:[0-9]+!)?          # epoch
332                 [0-9]+(?:\.[0-9]+)+   # release  (We have a + instead of a *)
333                 (?:                   # pre release
334                     [-_\.]?
335                     (a|b|c|rc|alpha|beta|pre|preview)
336                     [-_\.]?
337                     [0-9]*
338                 )?
339                 (?:                                   # post release
340                     (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
341                 )?
342                 (?:[-_\.]?dev[-_\.]?[0-9]*)?          # dev release
343             )
344             |
345             (?:
346                 # All other operators only allow a sub set of what the
347                 # (non)equality operators do. Specifically they do not allow
348                 # local versions to be specified nor do they allow the prefix
349                 # matching wild cards.
350                 (?<!==|!=|~=)         # We have special cases for these
351                                       # operators so we want to make sure they
352                                       # don't match here.
353
354                 \s*
355                 v?
356                 (?:[0-9]+!)?          # epoch
357                 [0-9]+(?:\.[0-9]+)*   # release
358                 (?:                   # pre release
359                     [-_\.]?
360                     (a|b|c|rc|alpha|beta|pre|preview)
361                     [-_\.]?
362                     [0-9]*
363                 )?
364                 (?:                                   # post release
365                     (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*)
366                 )?
367                 (?:[-_\.]?dev[-_\.]?[0-9]*)?          # dev release
368             )
369         )
370         \s*
371         $
372         """,
373         re.VERBOSE | re.IGNORECASE,
374     )
375
376     _operators = {
377         "~=": "compatible",
378         "==": "equal",
379         "!=": "not_equal",
380         "<=": "less_than_equal",
381         ">=": "greater_than_equal",
382         "<": "less_than",
383         ">": "greater_than",
384         "===": "arbitrary",
385     }
386
387     @_require_version_compare
388     def _compare_compatible(self, prospective, spec):
389         # Compatible releases have an equivalent combination of >= and ==. That
390         # is that ~=2.2 is equivalent to >=2.2,==2.*. This allows us to
391         # implement this in terms of the other specifiers instead of
392         # implementing it ourselves. The only thing we need to do is construct
393         # the other specifiers.
394
395         # We want everything but the last item in the version, but we want to
396         # ignore post and dev releases and we want to treat the pre-release as
397         # it's own separate segment.
398         prefix = ".".join(
399             list(
400                 itertools.takewhile(
401                     lambda x: (not x.startswith("post")
402                                and not x.startswith("dev")),
403                     _version_split(spec),
404                 )
405             )[:-1]
406         )
407
408         # Add the prefix notation to the end of our string
409         prefix += ".*"
410
411         return (self._get_operator(">=")(prospective, spec)
412                 and self._get_operator("==")(prospective, prefix))
413
414     @_require_version_compare
415     def _compare_equal(self, prospective, spec):
416         # We need special logic to handle prefix matching
417         if spec.endswith(".*"):
418             # Split the spec out by dots, and pretend that there is an implicit
419             # dot in between a release segment and a pre-release segment.
420             spec = _version_split(spec[:-2])  # Remove the trailing .*
421
422             # Split the prospective version out by dots, and pretend that there
423             # is an implicit dot in between a release segment and a pre-release
424             # segment.
425             prospective = _version_split(str(prospective))
426
427             # Shorten the prospective version to be the same length as the spec
428             # so that we can determine if the specifier is a prefix of the
429             # prospective version or not.
430             prospective = prospective[:len(spec)]
431
432             # Pad out our two sides with zeros so that they both equal the same
433             # length.
434             spec, prospective = _pad_version(spec, prospective)
435         else:
436             # Convert our spec string into a Version
437             spec = Version(spec)
438
439             # If the specifier does not have a local segment, then we want to
440             # act as if the prospective version also does not have a local
441             # segment.
442             if not spec.local:
443                 prospective = Version(prospective.public)
444
445         return prospective == spec
446
447     @_require_version_compare
448     def _compare_not_equal(self, prospective, spec):
449         return not self._compare_equal(prospective, spec)
450
451     @_require_version_compare
452     def _compare_less_than_equal(self, prospective, spec):
453         return prospective <= Version(spec)
454
455     @_require_version_compare
456     def _compare_greater_than_equal(self, prospective, spec):
457         return prospective >= Version(spec)
458
459     @_require_version_compare
460     def _compare_less_than(self, prospective, spec):
461         # Convert our spec to a Version instance, since we'll want to work with
462         # it as a version.
463         spec = Version(spec)
464
465         # Check to see if the prospective version is less than the spec
466         # version. If it's not we can short circuit and just return False now
467         # instead of doing extra unneeded work.
468         if not prospective < spec:
469             return False
470
471         # This special case is here so that, unless the specifier itself
472         # includes is a pre-release version, that we do not accept pre-release
473         # versions for the version mentioned in the specifier (e.g. <3.1 should
474         # not match 3.1.dev0, but should match 3.0.dev0).
475         if not spec.is_prerelease and prospective.is_prerelease:
476             if Version(prospective.base_version) == Version(spec.base_version):
477                 return False
478
479         # If we've gotten to here, it means that prospective version is both
480         # less than the spec version *and* it's not a pre-release of the same
481         # version in the spec.
482         return True
483
484     @_require_version_compare
485     def _compare_greater_than(self, prospective, spec):
486         # Convert our spec to a Version instance, since we'll want to work with
487         # it as a version.
488         spec = Version(spec)
489
490         # Check to see if the prospective version is greater than the spec
491         # version. If it's not we can short circuit and just return False now
492         # instead of doing extra unneeded work.
493         if not prospective > spec:
494             return False
495
496         # This special case is here so that, unless the specifier itself
497         # includes is a post-release version, that we do not accept
498         # post-release versions for the version mentioned in the specifier
499         # (e.g. >3.1 should not match 3.0.post0, but should match 3.2.post0).
500         if not spec.is_postrelease and prospective.is_postrelease:
501             if Version(prospective.base_version) == Version(spec.base_version):
502                 return False
503
504         # Ensure that we do not allow a local version of the version mentioned
505         # in the specifier, which is techincally greater than, to match.
506         if prospective.local is not None:
507             if Version(prospective.base_version) == Version(spec.base_version):
508                 return False
509
510         # If we've gotten to here, it means that prospective version is both
511         # greater than the spec version *and* it's not a pre-release of the
512         # same version in the spec.
513         return True
514
515     def _compare_arbitrary(self, prospective, spec):
516         return str(prospective).lower() == str(spec).lower()
517
518     @property
519     def prereleases(self):
520         # If there is an explicit prereleases set for this, then we'll just
521         # blindly use that.
522         if self._prereleases is not None:
523             return self._prereleases
524
525         # Look at all of our specifiers and determine if they are inclusive
526         # operators, and if they are if they are including an explicit
527         # prerelease.
528         operator, version = self._spec
529         if operator in ["==", ">=", "<=", "~="]:
530             # The == specifier can include a trailing .*, if it does we
531             # want to remove before parsing.
532             if operator == "==" and version.endswith(".*"):
533                 version = version[:-2]
534
535             # Parse the version, and if it is a pre-release than this
536             # specifier allows pre-releases.
537             if parse(version).is_prerelease:
538                 return True
539
540         return False
541
542     @prereleases.setter
543     def prereleases(self, value):
544         self._prereleases = value
545
546
547 _prefix_regex = re.compile(r"^([0-9]+)((?:a|b|c|rc)[0-9]+)$")
548
549
550 def _version_split(version):
551     result = []
552     for item in version.split("."):
553         match = _prefix_regex.search(item)
554         if match:
555             result.extend(match.groups())
556         else:
557             result.append(item)
558     return result
559
560
561 def _pad_version(left, right):
562     left_split, right_split = [], []
563
564     # Get the release segment of our versions
565     left_split.append(list(itertools.takewhile(lambda x: x.isdigit(), left)))
566     right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right)))
567
568     # Get the rest of our versions
569     left_split.append(left[len(left_split):])
570     right_split.append(left[len(right_split):])
571
572     # Insert our padding
573     left_split.insert(
574         1,
575         ["0"] * max(0, len(right_split[0]) - len(left_split[0])),
576     )
577     right_split.insert(
578         1,
579         ["0"] * max(0, len(left_split[0]) - len(right_split[0])),
580     )
581
582     return (
583         list(itertools.chain(*left_split)),
584         list(itertools.chain(*right_split)),
585     )
586
587
588 class SpecifierSet(BaseSpecifier):
589
590     def __init__(self, specifiers="", prereleases=None):
591         # Split on , to break each indidivual specifier into it's own item, and
592         # strip each item to remove leading/trailing whitespace.
593         specifiers = [s.strip() for s in specifiers.split(",") if s.strip()]
594
595         # Parsed each individual specifier, attempting first to make it a
596         # Specifier and falling back to a LegacySpecifier.
597         parsed = set()
598         for specifier in specifiers:
599             try:
600                 parsed.add(Specifier(specifier))
601             except InvalidSpecifier:
602                 parsed.add(LegacySpecifier(specifier))
603
604         # Turn our parsed specifiers into a frozen set and save them for later.
605         self._specs = frozenset(parsed)
606
607         # Store our prereleases value so we can use it later to determine if
608         # we accept prereleases or not.
609         self._prereleases = prereleases
610
611     def __repr__(self):
612         pre = (
613             ", prereleases={0!r}".format(self.prereleases)
614             if self._prereleases is not None
615             else ""
616         )
617
618         return "<SpecifierSet({0!r}{1})>".format(str(self), pre)
619
620     def __str__(self):
621         return ",".join(sorted(str(s) for s in self._specs))
622
623     def __hash__(self):
624         return hash(self._specs)
625
626     def __and__(self, other):
627         if isinstance(other, string_types):
628             other = SpecifierSet(other)
629         elif not isinstance(other, SpecifierSet):
630             return NotImplemented
631
632         specifier = SpecifierSet()
633         specifier._specs = frozenset(self._specs | other._specs)
634
635         if self._prereleases is None and other._prereleases is not None:
636             specifier._prereleases = other._prereleases
637         elif self._prereleases is not None and other._prereleases is None:
638             specifier._prereleases = self._prereleases
639         elif self._prereleases == other._prereleases:
640             specifier._prereleases = self._prereleases
641         else:
642             raise ValueError(
643                 "Cannot combine SpecifierSets with True and False prerelease "
644                 "overrides."
645             )
646
647         return specifier
648
649     def __eq__(self, other):
650         if isinstance(other, string_types):
651             other = SpecifierSet(other)
652         elif isinstance(other, _IndividualSpecifier):
653             other = SpecifierSet(str(other))
654         elif not isinstance(other, SpecifierSet):
655             return NotImplemented
656
657         return self._specs == other._specs
658
659     def __ne__(self, other):
660         if isinstance(other, string_types):
661             other = SpecifierSet(other)
662         elif isinstance(other, _IndividualSpecifier):
663             other = SpecifierSet(str(other))
664         elif not isinstance(other, SpecifierSet):
665             return NotImplemented
666
667         return self._specs != other._specs
668
669     @property
670     def prereleases(self):
671         # If we have been given an explicit prerelease modifier, then we'll
672         # pass that through here.
673         if self._prereleases is not None:
674             return self._prereleases
675
676         # Otherwise we'll see if any of the given specifiers accept
677         # prereleases, if any of them do we'll return True, otherwise False.
678         # Note: The use of any() here means that an empty set of specifiers
679         #       will always return False, this is an explicit design decision.
680         return any(s.prereleases for s in self._specs)
681
682     @prereleases.setter
683     def prereleases(self, value):
684         self._prereleases = value
685
686     def contains(self, item, prereleases=None):
687         # Ensure that our item is a Version or LegacyVersion instance.
688         if not isinstance(item, (LegacyVersion, Version)):
689             item = parse(item)
690
691         # We can determine if we're going to allow pre-releases by looking to
692         # see if any of the underlying items supports them. If none of them do
693         # and this item is a pre-release then we do not allow it and we can
694         # short circuit that here.
695         # Note: This means that 1.0.dev1 would not be contained in something
696         #       like >=1.0.devabc however it would be in >=1.0.debabc,>0.0.dev0
697         if (not (self.prereleases or prereleases)) and item.is_prerelease:
698             return False
699
700         # Determine if we're forcing a prerelease or not, we bypass
701         # self.prereleases here and use self._prereleases because we want to
702         # only take into consideration actual *forced* values. The underlying
703         # specifiers will handle the other logic.
704         # The logic here is: If prereleases is anything but None, we'll just
705         #                    go aheand and continue to use that. However if
706         #                    prereleases is None, then we'll use whatever the
707         #                    value of self._prereleases is as long as it is not
708         #                    None itself.
709         if prereleases is None and self._prereleases is not None:
710             prereleases = self._prereleases
711
712         # We simply dispatch to the underlying specs here to make sure that the
713         # given version is contained within all of them.
714         # Note: This use of all() here means that an empty set of specifiers
715         #       will always return True, this is an explicit design decision.
716         return all(
717             s.contains(item, prereleases=prereleases)
718             for s in self._specs
719         )
720
721     def filter(self, iterable, prereleases=None):
722         # Determine if we're forcing a prerelease or not, we bypass
723         # self.prereleases here and use self._prereleases because we want to
724         # only take into consideration actual *forced* values. The underlying
725         # specifiers will handle the other logic.
726         # The logic here is: If prereleases is anything but None, we'll just
727         #                    go aheand and continue to use that. However if
728         #                    prereleases is None, then we'll use whatever the
729         #                    value of self._prereleases is as long as it is not
730         #                    None itself.
731         if prereleases is None and self._prereleases is not None:
732             prereleases = self._prereleases
733
734         # If we have any specifiers, then we want to wrap our iterable in the
735         # filter method for each one, this will act as a logical AND amongst
736         # each specifier.
737         if self._specs:
738             for spec in self._specs:
739                 iterable = spec.filter(iterable, prereleases=prereleases)
740             return iterable
741         # If we do not have any specifiers, then we need to have a rough filter
742         # which will filter out any pre-releases, unless there are no final
743         # releases, and which will filter out LegacyVersion in general.
744         else:
745             filtered = []
746             found_prereleases = []
747
748             for item in iterable:
749                 # Ensure that we some kind of Version class for this item.
750                 if not isinstance(item, (LegacyVersion, Version)):
751                     parsed_version = parse(item)
752                 else:
753                     parsed_version = item
754
755                 # Filter out any item which is parsed as a LegacyVersion
756                 if isinstance(parsed_version, LegacyVersion):
757                     continue
758
759                 # Store any item which is a pre-release for later unless we've
760                 # already found a final version or we are accepting prereleases
761                 if parsed_version.is_prerelease and not prereleases:
762                     if not filtered:
763                         found_prereleases.append(item)
764                 else:
765                     filtered.append(item)
766
767             # If we've found no items except for pre-releases, then we'll go
768             # ahead and use the pre-releases
769             if not filtered and found_prereleases and prereleases is None:
770                 return found_prereleases
771
772             return filtered