ai]dZddlmZddlZddlZddlZddlmZmZm Z m Z m Z m Z ddl mZddlmZmZe eefZe de ZeeegefZd(dZd)dZd)dZGddeZGddejZGddeZejdZ d*dZ!d+dZ"d,d!Z#d-d%Z$Gd&d'eZ%dS).z .. testsetup:: from packaging.specifiers import Specifier, SpecifierSet, InvalidSpecifier from packaging.version import Version ) annotationsN)CallableFinalIterableIteratorTypeVarUnion)canonicalize_version)InvalidVersionVersionUnparsedVersionVar)boundversionUnparsedVersionreturnVersion | Nonectt|ts" t|}n#t$rYdSwxYw|SN) isinstancer r rs d/home/jenkins/workspace/simtester-sanitize/venv/lib/python3.11/site-packages/packaging/specifiers.py_coerce_versionrsO gw ' ' g&&GG   44  Ns ' 55r c.|dS)N)local __replace__rs r_public_versionr#s   T  * **c4|ddddS)N)prepostdevrrrs r _base_versionr$'s   4dD  I IIrceZdZdZdS)InvalidSpecifiera Raised when attempting to create a :class:`Specifier` with a specifier string that is invalid. >>> Specifier("lolwat") Traceback (most recent call last): ... packaging.specifiers.InvalidSpecifier: Invalid specifier: 'lolwat' N)__name__ __module__ __qualname____doc__rrr&r&+srr&c2eZdZdZdZeddZejddZ ejddZ ejdd Z eejddZ e j ddZ ejdd dZej dd!dZdS)" BaseSpecifierr+)_strrstrc t|S)z Internal property for match_argsr/selfs rr.zBaseSpecifier._str;s4yyrcdS)z Returns the str representation of this Specifier-like object. This should be representative of the Specifier itself. Nr+r2s r__str__zBaseSpecifier.__str__@rintcdS)zF Returns a hash value for this Specifier-like object. Nr+r2s r__hash__zBaseSpecifier.__hash__Gr6rotherobjectboolcdS)z Returns a boolean representing whether or not the two Specifier-like objects are equal. :param other: The other object to check against. Nr+r3r:s r__eq__zBaseSpecifier.__eq__Mr6r bool | NonecdS)zWhether or not pre-releases as a whole are allowed. This can be set to either ``True`` or ``False`` to explicitly enable or disable prereleases or it can be set to ``None`` (the default) to use default semantics. Nr+r2s r prereleaseszBaseSpecifier.prereleasesVr6rvalueNonecdS)zQSetter for :attr:`prereleases`. :param value: The value to set. Nr+r3rCs rrBzBaseSpecifier.prereleases_r6rNitemrBcdS)zR Determines if the given item is contained within this specifier. Nr+r3rGrBs rcontainszBaseSpecifier.containsfr6riterableIterable[UnparsedVersionVar]Iterator[UnparsedVersionVar]cdS)z Takes an iterable of items and filters them so that only items which are contained within this specifier are allowed in it. Nr+)r3rKrBs rfilterzBaseSpecifier.filterlr6rrr/rr7r:r;rr<rr@)rCr<rrDr)rGr/rBr@rr<rKrLrBr@rrM)r'r(r) __slots____match_args__propertyr.abcabstractmethodr5r9r?rBsetterrJrOr+rrr-r-7sOIN X                  X            QU       rr-) metaclassc eZdZUdZdZdZdZejdezezdzej ej zZ dddd d d d d dZ de d<dEdFdZdGdZdHdZedIdZejdJd!ZedKd"ZedKd#ZdKd$ZdKd%ZedLd'ZdMd)ZdNd-ZdOd0ZdPd2ZdPd3ZdPd4ZdPd5ZdPd6Z dQd8Z!dQd9Z"dRd;Z#dSd>Z$dTdUd@Z% dTdVdDZ&dS)W Specifiera?This class abstracts handling of version specifiers. .. tip:: It is generally not required to instantiate this manually. You should instead prefer to work with :class:`SpecifierSet` instead, which can parse comma-separated version specifiers (which is what package metadata contains). ) _prereleases_spec _spec_versionz8 (?P(~=|==|!=|<=|>=|<|>|===)) a (?P (?: # The identity operators allow for an escape hatch that will # do an exact string match of the version you wish to install. # This will not be parsed by PEP 440 and we cannot determine # any semantic meaning from it. This operator is discouraged # but included entirely as an escape hatch. (?<====) # Only match for the identity operator \s* [^\s;)]* # The arbitrary version can be just about anything, # we match everything except for whitespace, a # semi-colon for marker support, and a closing paren # since versions can be enclosed in them. ) | (?: # The (non)equality operators allow for wild card and local # versions to be specified so we have to define these two # operators separately to enable that. (?<===|!=) # Only match for equals and not equals \s* v? (?:[0-9]+!)? # epoch [0-9]+(?:\.[0-9]+)* # release # You cannot use a wild card and a pre-release, post-release, a dev or # local version together so group them with a | and make them optional. (?: \.\* # Wild card syntax of .* | (?: # pre release [-_\.]? (alpha|beta|preview|pre|a|b|c|rc) [-_\.]? [0-9]* )? (?: # post release (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) )? (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release (?:\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*)? # local )? ) | (?: # The compatible operator requires at least two digits in the # release segment. (?<=~=) # Only match for the compatible operator \s* v? (?:[0-9]+!)? # epoch [0-9]+(?:\.[0-9]+)+ # release (We have a + instead of a *) (?: # pre release [-_\.]? (alpha|beta|preview|pre|a|b|c|rc) [-_\.]? [0-9]* )? (?: # post release (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) )? (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release ) | (?: # All other operators only allow a sub set of what the # (non)equality operators do. Specifically they do not allow # local versions to be specified nor do they allow the prefix # matching wild cards. (?=<>===r _operatorsNspecr/rBr@rrDc$|j|}|std||d|df|_||_d|_dS)aInitialize a Specifier instance. :param spec: The string representation of a specifier which will be parsed and normalized before use. :param prereleases: This tells the specifier if it should accept prerelease versions if applicable or not. The default of ``None`` will autodetect it from the given specifiers. :raises InvalidSpecifier: If the given specifier is invalid (i.e. bad syntax). zInvalid specifier: operatorrN)_regex fullmatchr&groupstripr_r^r`)r3rrrBmatchs r__init__zSpecifier.__init__s %%d++ C"#A#A#ABB B KK # # ) ) + + KK " " ( ( * *'  (:>rrrc|j|jd|kr |jdSt|}|dS||f|_|S)zDOne element cache, as only one spec Version is needed per Specifier.Nrr )r`r)r3rversion_specifiers r_get_spec_versionzSpecifier._get_spec_versionsX   )d.@.Cw.N.N%a( (+G44  $4%'89  rr c8||}|J|S)zGet spec version, asserting it's valid (not for === operator). This method should only be called for operators where version strings are guaranteed to be valid PEP 440 versions (not ===). )r})r3r spec_versions r_require_spec_versionzSpecifier._require_spec_versions) --g66 '''rc|j|jS|j\}}|dkr?|dkr|drdS||}|dS|jrdSdS)Nrkrj.*FT)r^r_endswithr} is_prerelease)r3rt version_strrs rrBzSpecifier.prereleases%s   ($ $!% + t  4K$8$8$>$>u,,[99Gt$ turrCc||_dSrr^rFs rrBzSpecifier.prereleasesB!rc|jdS)z`The operator of this specifier. >>> Specifier("==1.2.3").operator '==' rr_r2s rrtzSpecifier.operatorFz!}rc|jdS)zaThe version of this specifier. >>> Specifier("==1.2.3").version '1.2.3' r rr2s rrzSpecifier.versionOrrcl|j d|jnd}d|jjdt ||dS)aTA representation of the Specifier that shows all internal state. >>> Specifier('>=1.0.0') =1.0.0')> >>> Specifier('>=1.0.0', prereleases=False) =1.0.0', prereleases=False)> >>> Specifier('>=1.0.0', prereleases=True) =1.0.0', prereleases=True)> N, prereleases=rqrm()>)r^rB __class__r'r/r3r!s r__repr__zSpecifier.__repr__XsT , 2T- 1 1 1 B4>*AASYYA#AAAArc dj|jS)zA string representation of the Specifier that can be round-tripped. >>> str(Specifier('>=1.0.0')) '>=1.0.0' >>> str(Specifier('>=1.0.0', prereleases=False)) '>=1.0.0' z{}{})formatr_r2s rr5zSpecifier.__str__jsv}dj))rtuple[str, str]c|j\}}|dks|dr||fS||}t||dk}||fS)Nrorristrip_trailing_zero)r_rrr )r3rtrrcanonical_versions r_canonical_speczSpecifier._canonical_spectsw J' u   0 0 6 6 W$ $11':: 0 x4/?   ***rr7c*t|jSr)hashrr2s rr9zSpecifier.__hash__sD()))rr:r;r<ct|tr; |t|}n3#t$r tcYSwxYwt||jstS|j|jkS)a>Whether or not the two Specifier-like objects are equal. :param other: The other object to check against. The value of :attr:`prereleases` is ignored. >>> Specifier("==1.2.3") == Specifier("== 1.2.3.0") True >>> (Specifier("==1.2.3", prereleases=False) == ... Specifier("==1.2.3", prereleases=True)) True >>> Specifier("==1.2.3") == "==1.2.3" True >>> Specifier("==1.2.3") == Specifier("==1.2.4") False >>> Specifier("==1.2.3") == Specifier("~=1.2.3") False )rr/rr&NotImplementedrr>s rr?zSpecifier.__eq__s& eS ! ! " &s5zz22# & & &%%%% &E4>22 "! !#u'<<>> "1.2.3" in Specifier(">=1.2.3") True >>> Version("1.2.3") in Specifier(">=1.2.3") True >>> "1.0.0" in Specifier(">=1.2.3") False >>> "1.3.0a1" in Specifier(">=1.2.3") True >>> "1.3.0a1" in Specifier(">=1.2.3", prereleases=True) True rJr3rGs r __contains__zSpecifier.__contains__3&}}T"""rrcftt||g|S)asReturn whether or not the item is contained in this specifier. :param item: The item to check for, which can be a version string or a :class:`Version` instance. :param prereleases: Whether or not to match prereleases with this Specifier. If set to ``None`` (the default), it will follow the recommendation from :pep:`440` and match prereleases, as there are no other versions. >>> Specifier(">=1.2.3").contains("1.2.3") True >>> Specifier(">=1.2.3").contains(Version("1.2.3")) True >>> Specifier(">=1.2.3").contains("1.0.0") False >>> Specifier(">=1.2.3").contains("1.3.0a1") True >>> Specifier(">=1.2.3", prereleases=False).contains("1.3.0a1") False >>> Specifier(">=1.2.3").contains("1.3.0a1") True rB)r<rrOrIs rrJzSpecifier.containsHs,2DdVEEFFGGGrrKrLrMc#Kg}d}||n|j}||j}|D]}t|}|+|jdkr|||jr|V>|||jr0|jr|rd}|V_||jdur|||s||jdur|Ed{VdSdSdSdS)aFilter items in the given iterable, that match the specifier. :param iterable: An iterable that can contain version strings and :class:`Version` instances. The items in the iterable will be filtered according to the specifier. :param prereleases: Whether or not to allow prereleases in the returned iterator. If set to ``None`` (the default), it will follow the recommendation from :pep:`440` and match prereleases if there are no other versions. >>> list(Specifier(">=1.2.3").filter(["1.2", "1.3", "1.5a1"])) ['1.3'] >>> list(Specifier(">=1.2.3").filter(["1.2", "1.2.3", "1.3", Version("1.4")])) ['1.2.3', '1.3', ] >>> list(Specifier(">=1.2.3").filter(["1.2", "1.5a1"])) ['1.5a1'] >>> list(Specifier(">=1.2.3").filter(["1.3", "1.5a1"], prereleases=True)) ['1.3', '1.5a1'] >>> list(Specifier(">=1.2.3", prereleases=True).filter(["1.3", "1.5a1"])) ['1.3', '1.5a1'] FNroT) rBrrtrrrrr^append) r3rKrBprereleases_versionsfound_non_prereleasesinclude_prereleasesrrparsed_versions rrOzSpecifier.filtercsP0 " %'2KK8H  !..t}==  9 9G,W55N%=E))d.E.ET\//)"MMM"">4<@@ 9%397J9,0)!MMMM (T->e-K-K(//888 & ,#!..+ + + + + + + + + +  , ,##..rrqN)rrr/rBr@rrD)rr/rr)rr/rr rSrCr@rrDrP)rrrQrR)rr/rr)rr rrr/rr<)rr rr/rr<)rrrrr/rr<)rGrrr<r)rGrrBr@rr<rT)'r'r(r)r*rU_operator_regex_str_version_regex_strrecompileVERBOSE IGNORECASErurp__annotations__rzr}rrWrBrZrtrrr5rr9r?rrrrrrrrrrrJrOr+rrr]r]vs;I \ |RZ$$'99FB R]"F "    J    >>>>>8 ! ! ! !X8""""XXBBBB$**** + + +X +****====:!!!!     (&/&/&/&/P::::PPPP PPPP 6    D====####*HHHHH8RV<,<,<,<,<,<,<,rr]z([0-9]+)((?:a|b|c|rc)[0-9]+)r/ list[str]cLg}|d\}}}||pd|dD][}t|}|r(||F||\|S)aSplit version into components. The split components are intended for version comparison. The logic does not attempt to retain the original version string, so joining the components back with :func:`_version_join` may not produce the original version string. !0.) rpartitionrsplit _prefix_regexrvextendgroups)rresultepochrrestrGrys rrrsF'',,NE1d MM%,3 3  ''--  MM%,,.. ) ) ) ) MM$     Mr componentsc>|^}}|dd|S)zJoin split version components into a version string. This function assumes the input came from :func:`_version_split`, where the first component must be the epoch (either empty or numeric), and all other components numeric. rr)join)rrrs rrrs+LED & &chhtnn & &&rsegmentr<c<tfddD S)Nc3BK|]}|VdSr) startswith).0rrs r z!_is_not_suffix..sB'-6""r)r#abrcr")any)rs`rrrs@1P rleftrighttuple[list[str], list[str]]c gg}}|ttjd||ttjd|||t |dd||t |dd|ddgt dt |dt |dz z|ddgt dt |dt |dz zttj|ttj|fS)Nc*|Srisdigitxs rz_pad_version..src*|Srr r s rr z_pad_version..s!))++rrr r) rrrrrinsertmaxchain from_iterable)rr left_split right_splits rrrs " Jd9./D/DdKKLLMMMtI/0E0EuMMNNOOOd3z!}--//0111uSQ00223444a#QKN(;(;c*Q->P>P(P!Q!QQRRRq3%#aZ]););c+a.>Q>Q)Q"R"RRSSS Y_ * *: 6 677 Y_ * *; 7 788 rceZdZdZdZ d&d'd Zed(d Zejd)dZd*dZ d*dZ d+dZ d,dZ d-dZ d+dZd.dZd/dZ d0d1d!Z d2d3d%ZdS)4 SpecifierSetzThis class abstracts handling of a set of version specifiers. It can be passed a single specifier (``>=3.0``), a comma-separated list of specifiers (``>=3.0,!=3.1``), or no specifier at all. )r^_specsrqN specifiersstr | Iterable[Specifier]rBr@rrDct|trGd|dD}tt t ||_nt||_||_dS)aInitialize a SpecifierSet instance. :param specifiers: The string representation of a specifier or a comma-separated list of specifiers which will be parsed and normalized before use. May also be an iterable of ``Specifier`` instances, which will be used as is. :param prereleases: This tells the SpecifierSet if it should accept prerelease versions if applicable or not. The default of ``None`` will autodetect it from the given specifiers. :raises InvalidSpecifier: If the given ``specifiers`` are not parseable than this exception will be raised. c^g|]*}||+Sr+)rxrss r z)SpecifierSet.__init__..s-VVVaAGGIIV VVVr,N)rr/r frozensetmapr]rr^)r3rrBsplit_specifierss rrzzSpecifierSet.__init__sz, j# & & 0 WV:3C3CC3H3HVVV $C 3C$D$DEEDKK$J//DK(rct|j|jS|jsdStd|jDrdSdS)Nc3$K|] }|jV dSrrrs rrz+SpecifierSet.prereleases..s$22q}222222rT)r^rrr2s rrBzSpecifierSet.prereleasessT   ($ $ { 4 22dk222 2 2 4trrCc||_dSrrrFs rrBzSpecifierSet.prereleases$rrr/cR|j d|jnd}dt||dS)aA representation of the specifier set that shows all internal state. Note that the ordering of the individual specifiers within the set may not match the input string. >>> SpecifierSet('>=1.0.0,!=2.0.0') =1.0.0')> >>> SpecifierSet('>=1.0.0,!=2.0.0', prereleases=False) =1.0.0', prereleases=False)> >>> SpecifierSet('>=1.0.0,!=2.0.0', prereleases=True) =1.0.0', prereleases=True)> Nrrqz>> str(SpecifierSet(">=1.0.0,!=1.0.1")) '!=1.0.1,>=1.0.0' >>> str(SpecifierSet(">=1.0.0,!=1.0.1", prereleases=False)) '!=1.0.1,>=1.0.0' rc34K|]}t|VdSrr1rs rrz'SpecifierSet.__str__..Hs(;;!s1vv;;;;;;r)rsortedrr2s rr5zSpecifierSet.__str__=s/xx;;t{;;;;;<<>> SpecifierSet(">=1.0.0,!=1.0.1") & '<=2.0.0,!=2.0.1' =1.0.0')> >>> SpecifierSet(">=1.0.0,!=1.0.1") & SpecifierSet('<=2.0.0,!=2.0.1') =1.0.0')> NzFCannot combine SpecifierSets with True and False prerelease overrides.)rr/rrr rr^ ValueError)r3r: specifiers r__and__zSpecifierSet.__and__Ms eS ! ! " ''EEE<00 "! ! NN $T[5<%?@@    $);)G%*%7I " "   )e.@.H  %"4 4 4%)%6I " "X rr;r<ct|ttfrtt|}nt|tstS|j|jkS)aWhether or not the two SpecifierSet-like objects are equal. :param other: The other object to check against. The value of :attr:`prereleases` is ignored. >>> SpecifierSet(">=1.0.0,!=1.0.1") == SpecifierSet(">=1.0.0,!=1.0.1") True >>> (SpecifierSet(">=1.0.0,!=1.0.1", prereleases=False) == ... SpecifierSet(">=1.0.0,!=1.0.1", prereleases=True)) True >>> SpecifierSet(">=1.0.0,!=1.0.1") == ">=1.0.0,!=1.0.1" True >>> SpecifierSet(">=1.0.0,!=1.0.1") == SpecifierSet(">=1.0.0") False >>> SpecifierSet(">=1.0.0,!=1.0.1") == SpecifierSet(">=1.0.0,!=1.0.2") False )rr/r]rrrr>s rr?zSpecifierSet.__eq__lsW& ec9- . . " U,,EEE<00 "! !{el**rc*t|jS)z7Returns the number of specifiers in this specifier set.)rrr2s r__len__zSpecifierSet.__len__s4;rIterator[Specifier]c*t|jS)z Returns an iterator over all the underlying :class:`Specifier` instances in this specifier set. >>> sorted(SpecifierSet(">=1.0.0,!=1.0.1"), key=str) [, =1.0.0')>] )iterrr2s r__iter__zSpecifierSet.__iter__sDK   rrGrc,||S)aqReturn whether or not the item is contained in this specifier. :param item: The item to check for. This is used for the ``in`` operator and behaves the same as :meth:`contains` with no ``prereleases`` argument passed. >>> "1.2.3" in SpecifierSet(">=1.0.0,!=1.0.1") True >>> Version("1.2.3") in SpecifierSet(">=1.0.0,!=1.0.1") True >>> "1.0.1" in SpecifierSet(">=1.0.0,!=1.0.1") False >>> "1.3.0a1" in SpecifierSet(">=1.0.0,!=1.0.1") True >>> "1.3.0a1" in SpecifierSet(">=1.0.0,!=1.0.1", prereleases=True) True rrs rrzSpecifierSet.__contains__rr installedct|}| |r |jrd}||n|}tt||g|S)aReturn whether or not the item is contained in this SpecifierSet. :param item: The item to check for, which can be a version string or a :class:`Version` instance. :param prereleases: Whether or not to match prereleases with this SpecifierSet. If set to ``None`` (the default), it will follow the recommendation from :pep:`440` and match prereleases, as there are no other versions. :param installed: Whether or not the item is installed. If set to ``True``, it will accept prerelease versions even if the specifier does not allow them. >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.2.3") True >>> SpecifierSet(">=1.0.0,!=1.0.1").contains(Version("1.2.3")) True >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.0.1") False >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.3.0a1") True >>> SpecifierSet(">=1.0.0,!=1.0.1", prereleases=False).contains("1.3.0a1") False >>> SpecifierSet(">=1.0.0,!=1.0.1").contains("1.3.0a1", prereleases=True) True NTr)rrr<rrO)r3rGrBr8r check_items rrJzSpecifierSet.containss_@"$''  9 1F K$_TT' Dj\{KKLLMMMrrKrLrMc ||j|j}|jr7|jD]}|||dn|}|t|Sn%|durt|S|dur fd|DSg}g}d}|D]r}t |}|+||||>|jr||[||d}st|r|n|S)aFilter items in the given iterable, that match the specifiers in this set. :param iterable: An iterable that can contain version strings and :class:`Version` instances. The items in the iterable will be filtered according to the specifier. :param prereleases: Whether or not to allow prereleases in the returned iterator. If set to ``None`` (the default), it will follow the recommendation from :pep:`440` and match prereleases if there are no other versions. >>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.3", "1.5a1"])) ['1.3'] >>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.3", Version("1.4")])) ['1.3', ] >>> list(SpecifierSet(">=1.2.3").filter(["1.2", "1.5a1"])) ['1.5a1'] >>> list(SpecifierSet(">=1.2.3").filter(["1.3", "1.5a1"], prereleases=True)) ['1.3', '1.5a1'] >>> list(SpecifierSet(">=1.2.3", prereleases=True).filter(["1.3", "1.5a1"])) ['1.3', '1.5a1'] An "empty" SpecifierSet will filter items based on the presence of prerelease versions in the set. >>> list(SpecifierSet("").filter(["1.3", "1.5a1"])) ['1.3'] >>> list(SpecifierSet("").filter(["1.5a1"])) ['1.5a1'] >>> list(SpecifierSet("", prereleases=True).filter(["1.3", "1.5a1"])) ['1.3', '1.5a1'] >>> list(SpecifierSet("").filter(["1.3", "1.5a1"], prereleases=True)) ['1.3', '1.5a1'] NTrFc3LK|]}t|xj|VdSr)rr)rrGrs rrz&SpecifierSet.filter..sN#24#8#88A"0BAAAAr)rBrrOr5rrr) r3rKrBrrfiltered_itemsfound_prereleasesfound_final_releaserGrrs @rrOzSpecifierSet.filtersN  4#3#?*K ;    ;;+2E$$;'&H~~%' d""H~~%e## (4668# + +D,T22N%%%d+++!((....- +!((....%%d+++&*##&9PNN?PQQQrr)rrrBr@rrDrSrrPrQ)r:r+rrrR)rr3)rGrrr<)NN)rGrrBr@r8r@rr<rrT)r'r(r)r*rUrzrWrBrZrr5r9r/r?r2r6rrJrOr+rrrrs +I13#'$($($($($(LX&""""5555* = = = =!!!!>++++4    !!!!####0$(!% &N&N&N&N&NRRV[R[R[R[R[R[R[Rrr)rrrr)rr rr )rr/rr)rrrr/)rr/rr<)rrrrrr)&r* __future__rrXrrtypingrrrrrr utilsr rr r r/rrr<rrrr$r-r&ABCMetar-r]rrrrrrrr+rrrDsN#"""""  FFFFFFFFFFFFFFFF'''''',,,,,,,, %W1IIIWcND01++++JJJJ     z   < < < < < ck< < < < ~i,i,i,i,i, i,i,i,X :;; ,'''' *KRKRKRKRKR=KRKRKRKRKRr