ÿØÿà JFIF    ÿÛ „  ( %!1"%)+...383-7(-.+  -%%--------+------------/----------------------------ÿÀ  ¶" ÿÄ     ÿÄ @    !1AQaq‘¡"±ÁÑð2’BRráS‚ñ3b¢CT²Ò #cÿÄ    ÿÄ '   1!AQ2a"‘±#ÿÚ   ? ò(/p‘—–¢·,M|¯G»R£üešT. ôŸEoCFñ‡ 4ÔkåóxR|µÁ¨ÓDà!Ç´µ˜‡p ÍQ‹§!þž^õWsŒy  åÁ§$á«%ºq˜™JyyË0y«^Ϗ -3ÃÏËÈ£Æ\P’ä„s&•‹Üs üô'àWt¹pñCp$bÚF`·7.^)¾!)ÒÙ˜–ÅÏš^h¾ø³·ìe±ŒaeÖ—Í,e=B}Jéߦ$$½—šÙÜCC¯¶è8β–Åkèwx LÉngT±æ¹£Ócœ¿Í/©Éÿ ‰ÚCÒ­mq;Tt¶–}0"zÖPcd1š­¤tˆ„ÐÓâqú[™öUCŠ2޿د­É(¸ßúçšmW,Ò ºf‹Ån™ÄLêÁ8üÁkÁ€L¥ÍuJ1œôrÂSŒÓöt!7EUíïb)AËi¬â-ÙHk8òÁiXYwÅ)O^"ÇØriÛô{»wRUKÙÏÚlÓ¬€‚’שT ] ªb—ÊîKC^×M“xùäñz¬zJ× {4[¹M'IÆeH1LCWÕ]œûº WDæà°OÅ‚¹c²ÞuA–rL`HšpCez‡V’— Ž‚Ë„–ñ­'µR0ÕÖ=À:±G»C\nÆÉ5*¢ †3šhQ4ýÒi$Õ1"Ü]¢p-q3zcQ$ªö¨¥æf›‘»´ÝÚHá„e²JÇ–iÊ:·à¬Øc5Åk»Laª*wi [0Ówk ¦a¦0Õ²ÅÅ‚T¸’³q:Æ<¹ú Ò˜Æ}2VE•Ѐp¡Ô3Úº …h³^LJºçì¥Ánó|˜ÖˆÎˆ+« ¦dø‘Mº–d\ªDðÛ„Ì×LÝ——Ð9Ç|•FèçVm™¨€™3õS–9Äå¢<̉Ìm¢±`·º˜&Z²ž Ë®D«¶»6™‰©­HÈ Àá«h­i³04æ’hxœi3ï¨(ÓL·†‹¶ËpŒ ƒÜÒ? :õdsÀ –3æÓ·Üjâ¬9—]8n¼&]I F£¼…ì–—Œ0v°LǐÅfÛ2TÖ’aµ˜N@ÖBSÏ^à´4-±°b×nÈÈœÆD=KdŒø…ÄÈK,›ÖR§fjü$^ÔÎ!„6^ s:Üun\ôkCÞò÷<—Lúl Í›G¹ÀPá¼Nc¡šÒ…ÙWͳœ±vÊáЄ×9‹P‰cEØ‘™›µŸP<×g1 º©Ø¬wiÁ^l5× I/';Ë+´Z‡ÓÄFÕp[Èð’ HÄ ó 9¬Dl4“é±Ï”V=^Hð;žLädÉa‚°Ë,#/Ž~²BÔÛ QãñQtIeórVB,ÏÂf‹4#Μc‹É3ZIÖ Œ¢¥·üxa‡Ãçè„jŠ[5 Ä!U?,3žÎ×…ðdÓ÷háŠA‰ìÄ4÷ÃÜZÃE{‰®+W\ZÍE[‰»µk»MÝ­`¢©†˜ÃV‹-f¢¡†¢a«eŠ%«Y¨©q%jâd,Ôq`) ¤¦…šˆ ¦E>0Ùb²t–Ÿ  ÷jsςҒKÈcø(é›;k(’#ôŒQ ™C> õ³M9óºÆµ¤çâ;uÀ)5>RÔ¸fÓ~Ȧ—’-$fe«"FâUˆÊwµPÏu w+"åÉó¨6s™Û9(À¨ù©hE°½†n`m~“@©›p!Vkhµ Á1šbEqqÊ@ºèl›2 –Yã%‘‚hÛ{a¶‡ÅÞM²¬çL34®Çl]®‹ŽØŒm'RÜe35æöˆ­Á­ cP9šeÁköo´L³Ì=p8]”‡B¶,šº|ɏdzXˆØk*ÇÚ{#ñ‰pã(€¶‡9ý'šÜ³½¯kƒ†Â’ëSOƒ•Å®H6+a¢µˆ‹Y¨b˜b+XˆÖ!°u!¢"µˆˆn2ˆ Å0Ä`Å Ô®c(ÓÜGº•Ä»Œ âWî%q.áÐÄ÷î%umÍ£+ÜQ,Vn¦-GphU¸¢X­&,Gt ·K¢ÅÅ·¥RÄÊÉbKn N­R2g$VµÕó Qr#–ÓZUÏð0ÎtÙÀœz ëöo“Îk¯n„T°"SÞ+³/…€½"ižãO%Í%&Δâ‘ËØ´IˆÓ°Ë‰ÞM3.™yçÁzit›`4C`k¢¼á!álÄï sÂ[×!¤l¾æo"ƒIÔ'@ªu)3›ô®“@Z à¾] üœ'‡4¸PÞkÁ-qÄH‰ÓÍBd´ÿ —¹°ÄA&ÊUC„öz‚‚RæŠtf¬>˜ÑidšEçÑL÷áý¡V±h§­c¿¥¨ƒ@g¼…Ýö^ÞËc.ž„æ“I[ ª+·zÐÒÚ,½Ð»¶€C›7jk$๖€Ž¾ÅÙpp¶ÍþéΤ ½ØÎŒq ñpæžÅ¥#Øâ49ÃÂK^MYV“,¶Éz_òæ:…;Õ«¦I3âJ£¤û5$7Èxün\â]Êe¯(Ÿ&Ž‹¶2<6Ćf× æ¢ƱqWı[(ÙÂŽç‚T7¨@ÈÉÍß‚ïÙ"&3TYlGށ†)†#5ŠA©^T2ÆÁ†)©†©†¤yGXÁ†©"†)©¼ÅV WS†#©]R–r‹q5ÕbâWþBh¯u+ªÅÄ×ü„nÑ^êkªÁj‰jeœWˆÕÕ`µDµ2Ì+Ä µDµµ5Ô{¤Þ0RF’H÷AÛ<ÊÁ§ ƈæ0Ñ£ê4 öÚµ[¬/1²€â<-¬šö²r×0o×w ´xÐÒË„ g01¬„åEM蛇Ã\6µE›‘fÙO k÷CºnÓ1`iîÒ² áÂ!ÑLÄÿ ³¬\õ*:M=Ç»c‹2[‰ØsÕLò\ŒK L^™üÄN\¶#» Ç\……ßïIœÉ$¸ÎñÍ®ÔHÇ Ûí/´>Li”„†g^$ 7NÍÑÑ2M2ªNg=k½Ð}Ÿl6‡ —JWˆ”ÞéT·+µ¦üÂFè¢Vs6ýÆ4»2+2IÝ9ô9®ÇGÙÇ1+Ä8;*Õ§ž½D*îÑWÚçá3Ma¤·ˆ¥t}š²Ü…Q+Æüµ8HíS”üxGéÁˆ¦Ël„éÈ 5 µÄƒ6äÜ(kIš¯S†fÖ&¸®×v|Äyˆ*禌Éù@7-®Ä[]ÎÖ¿ê`º…=:…žJVnݳvðÖKE¼‚ »mà ÷f®:Ë ™–4rð¡4` ܹçž~‹C=œ…¾Ïj|VDtK.ƒ"9 Ï ­–éXá³6WÒïIL-Ї Ç PK\`BearerTokenAuthorization.phpnu[getToken())) { throw new InvalidArgumentException( "Cannot authorize a request with an empty token" ); } $accessToken = $token->getToken(); return $request->withHeader('Authorization', "Bearer {$accessToken}"); } } PK\TokenAuthorization.phpnu[token = $token; $this->expires = $expires; } /** * Sets the state of a token object * * @param array $state array containing 'token' and 'expires' */ public static function __set_state(array $state) { return new self( $state['token'], $state['expires'] ); } /** * @return string */ public function getToken() { return $this->token; } /** * @return int */ public function getExpiration() { return $this->expires; } /** * @return bool */ public function isExpired() { return $this->expires !== null && time() >= $this->expires; } /** * @return array */ public function toArray() { return [ 'token' => $this->token, 'expires' => $this->expires ]; } /** * @return string */ public function serialize() { return json_encode($this->__serialize()); } /** * Sets the state of the object from serialized json data */ public function unserialize($serialized) { $data = json_decode($serialized, true); $this->__unserialize($data); } /** * @return array */ public function __serialize() { return $this->toArray(); } /** * Sets the state of this object from an array */ public function __unserialize($data) { $this->token = $data['token']; $this->expires = $data['expires']; } } PK\ҵ<< SsoToken.phpnu[refreshToken = $refreshToken; $this->clientId = $clientId; $this->clientSecret = $clientSecret; $this->registrationExpiresAt = $registrationExpiresAt; $this->region = $region; $this->startUrl = $startUrl; } /** * @return bool */ public function isExpired() { if (isset($this->registrationExpiresAt) && time() >= $this->registrationExpiresAt ) { return false; } return $this->expires !== null && time() >= $this->expires; } /** * @return string|null */ public function getRefreshToken() { return $this->refreshToken; } /** * @return string|null */ public function getClientId() { return $this->clientId; } /** * @return string|null */ public function getClientSecret() { return $this->clientSecret; } /** * @return int|null */ public function getRegistrationExpiresAt() { return $this->registrationExpiresAt; } /** * @return string|null */ public function getRegion() { return $this->region; } /** * @return string|null */ public function getStartUrl() { return $this->startUrl; } /** * Creates an instance of SsoToken from a token data. * * @param $tokenData * * @return SsoToken */ public static function fromTokenData($tokenData): SsoToken { return new SsoToken( $tokenData['accessToken'], \strtotime($tokenData['expiresAt']), isset($tokenData['refreshToken']) ? $tokenData['refreshToken'] : null, isset($tokenData['clientId']) ? $tokenData['clientId'] : null, isset($tokenData['clientSecret']) ? $tokenData['clientSecret'] : null, isset($tokenData['registrationExpiresAt']) ? $tokenData['registrationExpiresAt'] : null, isset($tokenData['region']) ? $tokenData['region'] : null, isset($tokenData['startUrl']) ? $tokenData['startUrl'] : null ); } } PK\ɿTokenInterface.phpnu[>ParsesIniTrait.phpnu[ $profile) { // standardize config profile names $name = str_replace('profile ', '', $name); $profileData[$name] = $profile; } return $profileData; } /** * Gets the environment's HOME directory if available. * * @return null|string */ private static function getHomeDir() { // On Linux/Unix-like systems, use the HOME environment variable if ($homeDir = getenv('HOME')) { return $homeDir; } // Get the HOMEDRIVE and HOMEPATH values for Windows hosts $homeDrive = getenv('HOMEDRIVE'); $homePath = getenv('HOMEPATH'); return ($homeDrive && $homePath) ? $homeDrive . $homePath : null; } } PK\uʧ%RefreshableTokenProviderInterface.phpnu[ * use Aws\Token\TokenProvider; * $provider = TokenProvider::defaultProvider(); * // Returns a TokenInterface or throws. * $token = $provider()->wait(); * * * Token providers can be composed to create a token using conditional * logic that can create different tokens in different environments. You * can compose multiple providers into a single provider using * {@see Aws\Token\TokenProvider::chain}. This function accepts * providers as variadic arguments and returns a new function that will invoke * each provider until a token is successfully returned. */ class TokenProvider { use ParsesIniTrait; const ENV_PROFILE = 'AWS_PROFILE'; /** * Create a default token provider tha checks for cached a SSO token from * the CLI * * This provider is automatically wrapped in a memoize function that caches * previously provided tokens. * * @param array $config Optional array of token provider options. * * @return callable */ public static function defaultProvider(array $config = []) { $cacheable = [ 'sso', ]; $defaultChain = []; if ( !isset($config['use_aws_shared_config_files']) || $config['use_aws_shared_config_files'] !== false ) { $profileName = getenv(self::ENV_PROFILE) ?: 'default'; $defaultChain['sso'] = self::sso( $profileName, self::getHomeDir() . '/.aws/config', $config ); } if (isset($config['token']) && $config['token'] instanceof CacheInterface ) { foreach ($cacheable as $provider) { if (isset($defaultChain[$provider])) { $defaultChain[$provider] = self::cache( $defaultChain[$provider], $config['token'], 'aws_cached_' . $provider . '_token' ); } } } return self::memoize( call_user_func_array( [TokenProvider::class, 'chain'], array_values($defaultChain) ) ); } /** * Create a token provider function from a static token. * * @param TokenInterface $token * * @return callable */ public static function fromToken(TokenInterface $token) { $promise = Promise\Create::promiseFor($token); return function () use ($promise) { return $promise; }; } /** * Creates an aggregate token provider that invokes the provided * variadic providers one after the other until a provider returns * a token. * * @return callable */ public static function chain() { $links = func_get_args(); //Common use case for when aws_shared_config_files is false if (empty($links)) { return function () { return Promise\Create::promiseFor(false); }; } return function () use ($links) { /** @var callable $parent */ $parent = array_shift($links); $promise = $parent(); while ($next = array_shift($links)) { $promise = $promise->otherwise($next); } return $promise; }; } /** * Wraps a token provider and caches a previously provided token. * Ensures that cached tokens are refreshed when they expire. * * @param callable $provider Token provider function to wrap. * @return callable */ public static function memoize(callable $provider) { return function () use ($provider) { static $result; static $isConstant; // Constant tokens will be returned constantly. if ($isConstant) { return $result; } // Create the initial promise that will be used as the cached value // until it expires. if (null === $result) { $result = $provider(); } // Return a token that could expire and refresh when needed. return $result ->then(function (TokenInterface $token) use ($provider, &$isConstant, &$result) { // Determine if the token is constant. if (!$token->getExpiration()) { $isConstant = true; return $token; } if (!$token->isExpired()) { return $token; } return $result = $provider(); }) ->otherwise(function($reason) use (&$result) { // Cleanup rejected promise. $result = null; return Promise\Create::promiseFor(null); }); }; } /** * Wraps a token provider and saves provided token in an * instance of Aws\CacheInterface. Forwards calls when no token found * in cache and updates cache with the results. * * @param callable $provider Token provider function to wrap * @param CacheInterface $cache Cache to store the token * @param string|null $cacheKey (optional) Cache key to use * * @return callable */ public static function cache( callable $provider, CacheInterface $cache, $cacheKey = null ) { $cacheKey = $cacheKey ?: 'aws_cached_token'; return function () use ($provider, $cache, $cacheKey) { $found = $cache->get($cacheKey); if (is_array($found) && isset($found['token'])) { $foundToken = $found['token']; if ($foundToken instanceof TokenInterface) { if (!$foundToken->isExpired()) { return Promise\Create::promiseFor($foundToken); } if (isset($found['refreshMethod']) && is_callable($found['refreshMethod'])) { return Promise\Create::promiseFor($found['refreshMethod']()); } } } return $provider() ->then(function (TokenInterface $token) use ( $cache, $cacheKey ) { $cache->set( $cacheKey, $token, null === $token->getExpiration() ? 0 : $token->getExpiration() - time() ); return $token; }); }; } /** * Gets profiles from the ~/.aws/config ini file */ private static function loadDefaultProfiles() { $profiles = []; $configFile = self::getHomeDir() . '/.aws/config'; if (file_exists($configFile)) { $configProfileData = \Aws\parse_ini_file($configFile, true, INI_SCANNER_RAW); foreach ($configProfileData as $name => $profile) { // standardize config profile names $name = str_replace('profile ', '', $name); if (!isset($profiles[$name])) { $profiles[$name] = $profile; } } } return $profiles; } private static function reject($msg) { return new Promise\RejectedPromise(new TokenException($msg)); } /** * Token provider that creates a token from cached sso credentials * * @param string $profileName the name of the ini profile name * @param string $filename the location of the ini file * @param array $config configuration options * * @return SsoTokenProvider * @see Aws\Token\SsoTokenProvider for $config details. */ public static function sso($profileName, $filename, $config = []) { $ssoClient = isset($config['ssoClient']) ? $config['ssoClient'] : null; return new SsoTokenProvider($profileName, $filename, $ssoClient); } } PK\%%%%SsoTokenProvider.phpnu[profileName = $this->resolveProfileName($profileName); $this->configFilePath = $this->resolveConfigFile($configFilePath); $this->ssoOidcClient = $ssoOidcClient; } /** * This method resolves the profile name to be used. The * profile provided as instantiation argument takes precedence, * followed by AWS_PROFILE env variable, otherwise `default` is * used. * * @param string|null $argProfileName The profile provided as argument. * * @return string */ private function resolveProfileName($argProfileName): string { if (empty($argProfileName)) { return getenv(self::ENV_PROFILE) ?: 'default'; } else { return $argProfileName; } } /** * This method resolves the config file from where the profiles * are going to be loaded from. If $argFileName is not empty then, * it takes precedence over the default config file location. * * @param string|null $argConfigFilePath The config path provided as argument. * * @return string */ private function resolveConfigFile($argConfigFilePath): string { if (empty($argConfigFilePath)) { return self::getHomeDir() . '/.aws/config'; } else{ return $argConfigFilePath; } } /** * Loads cached sso credentials. * * @return Promise\PromiseInterface */ public function __invoke() { return Promise\Coroutine::of(function () { if (empty($this->configFilePath) || !is_readable($this->configFilePath)) { throw new TokenException("Cannot read profiles from {$this->configFilePath}"); } $profiles = self::loadProfiles($this->configFilePath); if (!isset($profiles[$this->profileName])) { throw new TokenException("Profile `{$this->profileName}` does not exist in {$this->configFilePath}."); } $profile = $profiles[$this->profileName]; if (empty($profile['sso_session'])) { throw new TokenException( "Profile `{$this->profileName}` in {$this->configFilePath} must contain an sso_session." ); } $ssoSessionName = $profile['sso_session']; $this->ssoSessionName = $ssoSessionName; $profileSsoSession = 'sso-session ' . $ssoSessionName; if (empty($profiles[$profileSsoSession])) { throw new TokenException( "Sso session `{$ssoSessionName}` does not exist in {$this->configFilePath}" ); } $sessionProfileData = $profiles[$profileSsoSession]; foreach (['sso_start_url', 'sso_region'] as $requiredProp) { if (empty($sessionProfileData[$requiredProp])) { throw new TokenException( "Sso session `{$ssoSessionName}` in {$this->configFilePath} is missing the required property `{$requiredProp}`" ); } } $tokenData = $this->refresh(); $tokenLocation = self::getTokenLocation($ssoSessionName); $this->validateTokenData($tokenLocation, $tokenData); $ssoToken = SsoToken::fromTokenData($tokenData); // To make sure the token is not expired if ($ssoToken->isExpired()) { throw new TokenException("Cached SSO token returned an expired token."); } yield $ssoToken; }); } /** * This method attempt to refresh when possible. * If a refresh is not possible then it just returns * the current token data as it is. * * @return array * @throws TokenException */ public function refresh(): array { $tokenLocation = self::getTokenLocation($this->ssoSessionName); $tokenData = $this->getTokenData($tokenLocation); if (!$this->shouldAttemptRefresh()) { return $tokenData; } if (null === $this->ssoOidcClient) { throw new TokenException( "Cannot refresh this token without an 'ssooidcClient' " ); } foreach (['clientId', 'clientSecret', 'refreshToken'] as $requiredProp) { if (empty($tokenData[$requiredProp])) { throw new TokenException( "Cannot refresh this token without `{$requiredProp}` being set" ); } } $response = $this->ssoOidcClient->createToken([ 'clientId' => $tokenData['clientId'], 'clientSecret' => $tokenData['clientSecret'], 'grantType' => 'refresh_token', // REQUIRED 'refreshToken' => $tokenData['refreshToken'], ]); if ($response['@metadata']['statusCode'] !== 200) { throw new TokenException('Unable to create a new sso token'); } $tokenData['accessToken'] = $response['accessToken']; $tokenData['expiresAt'] = time () + $response['expiresIn']; $tokenData['refreshToken'] = $response['refreshToken']; return $this->writeNewTokenDataToDisk($tokenData, $tokenLocation); } /** * This method checks for whether a token refresh should happen. * It will return true just if more than 30 seconds has happened * since last refresh, and if the expiration is within a 5-minutes * window from the current time. * * @return bool */ public function shouldAttemptRefresh(): bool { $tokenLocation = self::getTokenLocation($this->ssoSessionName); $tokenData = $this->getTokenData($tokenLocation); if (empty($tokenData['expiresAt'])) { throw new TokenException( "Token file at $tokenLocation must contain an expiration date" ); } $tokenExpiresAt = strtotime($tokenData['expiresAt']); $lastRefreshAt = filemtime($tokenLocation); $now = \time(); // If last refresh happened after 30 seconds // and if the token expiration is in the 5 minutes window return ($now - $lastRefreshAt) > self::REFRESH_ATTEMPT_WINDOW_IN_SECS && ($tokenExpiresAt - $now) < self::REFRESH_WINDOW_IN_SECS; } /** * @param $sso_session * @return string */ public static function getTokenLocation($sso_session): string { return self::getHomeDir() . '/.aws/sso/cache/' . mb_convert_encoding(sha1($sso_session), "UTF-8") . ".json"; } /** * @param $tokenLocation * @return array */ function getTokenData($tokenLocation): array { if (empty($tokenLocation) || !is_readable($tokenLocation)) { throw new TokenException("Unable to read token file at {$tokenLocation}"); } return json_decode(file_get_contents($tokenLocation), true); } /** * @param $tokenData * @param $tokenLocation * @return mixed */ private function validateTokenData($tokenLocation, $tokenData) { foreach (['accessToken', 'expiresAt'] as $requiredProp) { if (empty($tokenData[$requiredProp])) { throw new TokenException( "Token file at {$tokenLocation} must contain the required property `{$requiredProp}`" ); } } $expiration = strtotime($tokenData['expiresAt']); if ($expiration === false) { throw new TokenException("Cached SSO token returned an invalid expiration"); } elseif ($expiration < time()) { throw new TokenException("Cached SSO token returned an expired token"); } return $tokenData; } /** * @param array $tokenData * @param string $tokenLocation * * @return array */ private function writeNewTokenDataToDisk(array $tokenData, $tokenLocation): array { $tokenData['expiresAt'] = gmdate( 'Y-m-d\TH:i:s\Z', $tokenData['expiresAt'] ); file_put_contents($tokenLocation, json_encode(array_filter($tokenData))); return $tokenData; } } PKjM\Ol Stack.phpnu[branchPruner = $branchPruner; } /** * Return the number of entries on the stack. */ public function count(): int { return $this->count; } /** * Push a new entry onto the stack. */ public function push(string $type, mixed $value, ?string $reference = null): void { $stackItem = $this->getStackItem($type, $value, $reference); $this->stack[$this->count++] = $stackItem; if ($type === 'Function') { $localeFunction = Calculation::localeFunc($value); if ($localeFunction != $value) { $this->stack[($this->count - 1)]['localeValue'] = $localeFunction; } } } public function pushStackItem(array $stackItem): void { $this->stack[$this->count++] = $stackItem; } public function getStackItem(string $type, mixed $value, ?string $reference = null): array { $stackItem = [ 'type' => $type, 'value' => $value, 'reference' => $reference, ]; // will store the result under this alias $storeKey = $this->branchPruner->currentCondition(); if (isset($storeKey) || $reference === 'NULL') { $stackItem['storeKey'] = $storeKey; } // will only run computation if the matching store key is true $onlyIf = $this->branchPruner->currentOnlyIf(); if (isset($onlyIf) || $reference === 'NULL') { $stackItem['onlyIf'] = $onlyIf; } // will only run computation if the matching store key is false $onlyIfNot = $this->branchPruner->currentOnlyIfNot(); if (isset($onlyIfNot) || $reference === 'NULL') { $stackItem['onlyIfNot'] = $onlyIfNot; } return $stackItem; } /** * Pop the last entry from the stack. */ public function pop(): ?array { if ($this->count > 0) { return $this->stack[--$this->count]; } return null; } /** * Return an entry from the stack without removing it. */ public function last(int $n = 1): ?array { if ($this->count - $n < 0) { return null; } return $this->stack[$this->count - $n]; } /** * Clear the stack. */ public function clear(): void { $this->stack = []; $this->count = 0; } } PK\`BearerTokenAuthorization.phpnu[PK\TTokenAuthorization.phpnu[PK\9 Token.phpnu[PK\ҵ<< SsoToken.phpnu[PK\ɿTokenInterface.phpnu[PK\>>Z!ParsesIniTrait.phpnu[PK\uʧ%&RefreshableTokenProviderInterface.phpnu[PK\p$r!r!(TokenProvider.phpnu[PK\%%%%JSsoTokenProvider.phpnu[PKjM\Ol oStack.phpnu[PK >{